/mnt/user-data/adam/aztec-packages/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // === AUDIT STATUS === |
2 | | // internal: { status: not started, auditors: [], date: YYYY-MM-DD } |
3 | | // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } |
4 | | // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } |
5 | | // ===================== |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include "barretenberg/common/assert.hpp" |
10 | | #include "barretenberg/common/zip_view.hpp" |
11 | | #include "barretenberg/numeric/uint256/uint256.hpp" |
12 | | #include "barretenberg/numeric/uintx/uintx.hpp" |
13 | | #include <tuple> |
14 | | |
15 | | #include "../circuit_builders/circuit_builders.hpp" |
16 | | #include "bigfield.hpp" |
17 | | |
18 | | #include "../bit_array/bit_array.hpp" |
19 | | #include "../field/field.hpp" |
20 | | #include "barretenberg/transcript/origin_tag.hpp" |
21 | | |
22 | | namespace bb::stdlib { |
23 | | |
24 | | template <typename Builder, typename T> |
25 | | bigfield<Builder, T>::bigfield(Builder* parent_context) |
26 | | : context(parent_context) |
27 | | , binary_basis_limbs{ Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)) } |
28 | | , prime_basis_limb(context, 0) |
29 | 10.1M | {}_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_ Line | Count | Source | 29 | 9.36M | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_ Line | Count | Source | 29 | 1.23k | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_ Line | Count | Source | 29 | 130 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_ Line | Count | Source | 29 | 31.9k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_ Line | Count | Source | 29 | 279 | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_ Line | Count | Source | 29 | 694k | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_ Line | Count | Source | 29 | 5.61k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_ Line | Count | Source | 29 | 53.0k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_ Line | Count | Source | 29 | 115 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_ |
30 | | |
31 | | template <typename Builder, typename T> |
32 | | bigfield<Builder, T>::bigfield(Builder* parent_context, const uint256_t& value) |
33 | | : context(parent_context) |
34 | | , binary_basis_limbs{ Limb(bb::fr(value.slice(0, NUM_LIMB_BITS))), |
35 | | Limb(bb::fr(value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2))), |
36 | | Limb(bb::fr(value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3))), |
37 | | Limb(bb::fr(value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4))) } |
38 | | , prime_basis_limb(context, value) |
39 | 3.03M | { |
40 | 3.03M | ASSERT(value < modulus); |
41 | 3.03M | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 2.76M | { | 40 | 2.76M | ASSERT(value < modulus); | 41 | 2.76M | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 824 | { | 40 | 824 | ASSERT(value < modulus); | 41 | 824 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 75 | { | 40 | 75 | ASSERT(value < modulus); | 41 | 75 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 10.9k | { | 40 | 10.9k | ASSERT(value < modulus); | 41 | 10.9k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 168 | { | 40 | 168 | ASSERT(value < modulus); | 41 | 168 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 243k | { | 40 | 243k | ASSERT(value < modulus); | 41 | 243k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 3.31k | { | 40 | 3.31k | ASSERT(value < modulus); | 41 | 3.31k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 16.0k | { | 40 | 16.0k | ASSERT(value < modulus); | 41 | 16.0k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE Line | Count | Source | 39 | 103 | { | 40 | 103 | ASSERT(value < modulus); | 41 | 103 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE |
42 | | |
43 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/850): audit the evaluate_linear_identity function |
44 | | template <typename Builder, typename T> |
45 | | bigfield<Builder, T>::bigfield(const field_t<Builder>& low_bits_in, |
46 | | const field_t<Builder>& high_bits_in, |
47 | | const bool can_overflow, |
48 | | const size_t maximum_bitlength) |
49 | 51.7k | { |
50 | 51.7k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); |
51 | 51.7k | ASSERT((can_overflow == true && maximum_bitlength == 0) || |
52 | 0 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); |
53 | | |
54 | | // Check that the values of two parts are within specified bounds |
55 | 51.7k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); |
56 | 51.7k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); |
57 | | |
58 | 51.7k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; |
59 | 0 | field_t<Builder> limb_0(context); |
60 | 0 | field_t<Builder> limb_1(context); |
61 | 0 | field_t<Builder> limb_2(context); |
62 | 0 | field_t<Builder> limb_3(context); |
63 | 51.7k | if (!low_bits_in.is_constant()) { |
64 | 51.2k | std::vector<uint32_t> low_accumulator; |
65 | 51.2k | if constexpr (HasPlookup<Builder>) { |
66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 |
67 | 51.2k | const auto limb_witnesses = |
68 | 51.2k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); |
69 | 51.2k | limb_0.witness_index = limb_witnesses[0]; |
70 | 51.2k | limb_1.witness_index = limb_witnesses[1]; |
71 | 51.2k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); |
72 | | |
73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits |
74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, |
75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); |
76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb |
77 | | // size |
78 | | // // here |
79 | | // ASSERT(low_accumulator.size() % 2 == 0); |
80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; |
81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? |
82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; |
83 | 51.2k | } else { |
84 | 51.2k | size_t mid_index; |
85 | 51.2k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), |
86 | 51.2k | static_cast<size_t>(NUM_LIMB_BITS * 2), |
87 | 51.2k | "bigfield: low_bits_in too large."); |
88 | 51.2k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); |
89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb |
90 | | // value |
91 | 51.2k | limb_1.witness_index = low_accumulator[mid_index]; |
92 | | // We can get the first half bits of low_bits_in from the variables we already created |
93 | 51.2k | limb_0 = (low_bits_in - (limb_1 * shift_1)); |
94 | 51.2k | } |
95 | 51.2k | } else { |
96 | 468 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); |
97 | 468 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); |
98 | 468 | limb_0 = field_t(context, bb::fr(slice_0)); |
99 | 468 | limb_1 = field_t(context, bb::fr(slice_1)); |
100 | 468 | } |
101 | | |
102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each |
103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == |
104 | | // false) |
105 | 51.7k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; |
106 | | |
107 | | // if maximum_bitlength is set, this supercedes can_overflow |
108 | 51.7k | if (maximum_bitlength > 0) { |
109 | 468 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); |
110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); |
111 | 0 | } |
112 | | // We create the high limb values similar to the low limb ones above |
113 | 0 | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; |
114 | 51.7k | if (!high_bits_in.is_constant()) { |
115 | | |
116 | 51.2k | std::vector<uint32_t> high_accumulator; |
117 | 51.2k | if constexpr (HasPlookup<Builder>) { |
118 | 51.2k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( |
119 | 51.2k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); |
120 | 51.2k | limb_2.witness_index = limb_witnesses[0]; |
121 | 51.2k | limb_3.witness_index = limb_witnesses[1]; |
122 | 51.2k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); |
123 | | |
124 | 51.2k | } else { |
125 | 51.2k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), |
126 | 51.2k | static_cast<size_t>(num_high_limb_bits), |
127 | 51.2k | "bigfield: high_bits_in too large."); |
128 | | |
129 | 51.2k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; |
130 | 51.2k | limb_2 = (high_bits_in - (limb_3 * shift_1)); |
131 | 51.2k | } |
132 | 51.2k | } else { |
133 | 468 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); |
134 | 468 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); |
135 | 468 | limb_2 = field_t(context, bb::fr(slice_2)); |
136 | 468 | limb_3 = field_t(context, bb::fr(slice_3)); |
137 | 468 | } |
138 | 0 | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); |
139 | 0 | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); |
140 | 0 | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); |
141 | 51.7k | if (maximum_bitlength > 0) { |
142 | 468 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; |
143 | 468 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); |
144 | 51.2k | } else { |
145 | 51.2k | binary_basis_limbs[3] = |
146 | 51.2k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); |
147 | 51.2k | } |
148 | 0 | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); |
149 | 0 | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); |
150 | 0 | set_origin_tag(new_tag); |
151 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm Line | Count | Source | 49 | 43.0k | { | 50 | 43.0k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 43.0k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 43.0k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 43.0k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 43.0k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 43.0k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 43.0k | field_t<Builder> limb_0(context); | 60 | 43.0k | field_t<Builder> limb_1(context); | 61 | 43.0k | field_t<Builder> limb_2(context); | 62 | 43.0k | field_t<Builder> limb_3(context); | 63 | 43.0k | if (!low_bits_in.is_constant()) { | 64 | 42.9k | std::vector<uint32_t> low_accumulator; | 65 | 42.9k | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 42.9k | const auto limb_witnesses = | 68 | 42.9k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 42.9k | limb_0.witness_index = limb_witnesses[0]; | 70 | 42.9k | limb_1.witness_index = limb_witnesses[1]; | 71 | 42.9k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 42.9k | } else { | 84 | 42.9k | size_t mid_index; | 85 | 42.9k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 42.9k | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 42.9k | "bigfield: low_bits_in too large."); | 88 | 42.9k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 42.9k | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 42.9k | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 42.9k | } | 95 | 42.9k | } else { | 96 | 9 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 9 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 9 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 9 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 9 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 43.0k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 43.0k | if (maximum_bitlength > 0) { | 109 | 136 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 136 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 136 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 43.0k | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 43.0k | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 42.9k | std::vector<uint32_t> high_accumulator; | 117 | 42.9k | if constexpr (HasPlookup<Builder>) { | 118 | 42.9k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 42.9k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 42.9k | limb_2.witness_index = limb_witnesses[0]; | 121 | 42.9k | limb_3.witness_index = limb_witnesses[1]; | 122 | 42.9k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 42.9k | } else { | 125 | 42.9k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 42.9k | static_cast<size_t>(num_high_limb_bits), | 127 | 42.9k | "bigfield: high_bits_in too large."); | 128 | | | 129 | 42.9k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 42.9k | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 42.9k | } | 132 | 42.9k | } else { | 133 | 9 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 9 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 9 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 9 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 9 | } | 138 | 43.0k | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 43.0k | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 43.0k | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 43.0k | if (maximum_bitlength > 0) { | 142 | 136 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 136 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 42.8k | } else { | 145 | 42.8k | binary_basis_limbs[3] = | 146 | 42.8k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 42.8k | } | 148 | 43.0k | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 43.0k | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 43.0k | set_origin_tag(new_tag); | 151 | 43.0k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm Line | Count | Source | 49 | 1.29k | { | 50 | 1.29k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 1.29k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 1.29k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 1.29k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 1.29k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 1.29k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 1.29k | field_t<Builder> limb_0(context); | 60 | 1.29k | field_t<Builder> limb_1(context); | 61 | 1.29k | field_t<Builder> limb_2(context); | 62 | 1.29k | field_t<Builder> limb_3(context); | 63 | 1.29k | if (!low_bits_in.is_constant()) { | 64 | 1.29k | std::vector<uint32_t> low_accumulator; | 65 | 1.29k | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 1.29k | const auto limb_witnesses = | 68 | 1.29k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 1.29k | limb_0.witness_index = limb_witnesses[0]; | 70 | 1.29k | limb_1.witness_index = limb_witnesses[1]; | 71 | 1.29k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 1.29k | } else { | 84 | 1.29k | size_t mid_index; | 85 | 1.29k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 1.29k | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 1.29k | "bigfield: low_bits_in too large."); | 88 | 1.29k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 1.29k | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 1.29k | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 1.29k | } | 95 | 1.29k | } else { | 96 | 0 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 0 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 0 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 0 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 0 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 1.29k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 1.29k | if (maximum_bitlength > 0) { | 109 | 322 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 322 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 322 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 1.29k | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 1.29k | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 1.29k | std::vector<uint32_t> high_accumulator; | 117 | 1.29k | if constexpr (HasPlookup<Builder>) { | 118 | 1.29k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 1.29k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 1.29k | limb_2.witness_index = limb_witnesses[0]; | 121 | 1.29k | limb_3.witness_index = limb_witnesses[1]; | 122 | 1.29k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 1.29k | } else { | 125 | 1.29k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 1.29k | static_cast<size_t>(num_high_limb_bits), | 127 | 1.29k | "bigfield: high_bits_in too large."); | 128 | | | 129 | 1.29k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 1.29k | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 1.29k | } | 132 | 1.29k | } else { | 133 | 0 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 0 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 0 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 0 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 0 | } | 138 | 1.29k | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 1.29k | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 1.29k | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 1.29k | if (maximum_bitlength > 0) { | 142 | 322 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 322 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 971 | } else { | 145 | 971 | binary_basis_limbs[3] = | 146 | 971 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 971 | } | 148 | 1.29k | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 1.29k | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 1.29k | set_origin_tag(new_tag); | 151 | 1.29k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm Line | Count | Source | 49 | 1.88k | { | 50 | 1.88k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 1.88k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 1.88k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 1.88k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 1.88k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 1.88k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 1.88k | field_t<Builder> limb_0(context); | 60 | 1.88k | field_t<Builder> limb_1(context); | 61 | 1.88k | field_t<Builder> limb_2(context); | 62 | 1.88k | field_t<Builder> limb_3(context); | 63 | 1.88k | if (!low_bits_in.is_constant()) { | 64 | 1.88k | std::vector<uint32_t> low_accumulator; | 65 | 1.88k | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 1.88k | const auto limb_witnesses = | 68 | 1.88k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 1.88k | limb_0.witness_index = limb_witnesses[0]; | 70 | 1.88k | limb_1.witness_index = limb_witnesses[1]; | 71 | 1.88k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 1.88k | } else { | 84 | 1.88k | size_t mid_index; | 85 | 1.88k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 1.88k | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 1.88k | "bigfield: low_bits_in too large."); | 88 | 1.88k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 1.88k | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 1.88k | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 1.88k | } | 95 | 1.88k | } else { | 96 | 9 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 9 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 9 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 9 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 9 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 1.88k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 1.88k | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 1.88k | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 1.88k | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 1.88k | std::vector<uint32_t> high_accumulator; | 117 | 1.88k | if constexpr (HasPlookup<Builder>) { | 118 | 1.88k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 1.88k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 1.88k | limb_2.witness_index = limb_witnesses[0]; | 121 | 1.88k | limb_3.witness_index = limb_witnesses[1]; | 122 | 1.88k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 1.88k | } else { | 125 | 1.88k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 1.88k | static_cast<size_t>(num_high_limb_bits), | 127 | 1.88k | "bigfield: high_bits_in too large."); | 128 | | | 129 | 1.88k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 1.88k | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 1.88k | } | 132 | 1.88k | } else { | 133 | 9 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 9 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 9 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 9 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 9 | } | 138 | 1.88k | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 1.88k | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 1.88k | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 1.88k | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 1.88k | } else { | 145 | 1.88k | binary_basis_limbs[3] = | 146 | 1.88k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 1.88k | } | 148 | 1.88k | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 1.88k | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 1.88k | set_origin_tag(new_tag); | 151 | 1.88k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm Line | Count | Source | 49 | 166 | { | 50 | 166 | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 166 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 166 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 166 | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 166 | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 166 | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 166 | field_t<Builder> limb_0(context); | 60 | 166 | field_t<Builder> limb_1(context); | 61 | 166 | field_t<Builder> limb_2(context); | 62 | 166 | field_t<Builder> limb_3(context); | 63 | 166 | if (!low_bits_in.is_constant()) { | 64 | 160 | std::vector<uint32_t> low_accumulator; | 65 | 160 | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 160 | const auto limb_witnesses = | 68 | 160 | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 160 | limb_0.witness_index = limb_witnesses[0]; | 70 | 160 | limb_1.witness_index = limb_witnesses[1]; | 71 | 160 | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 160 | } else { | 84 | 160 | size_t mid_index; | 85 | 160 | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 160 | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 160 | "bigfield: low_bits_in too large."); | 88 | 160 | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 160 | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 160 | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 160 | } | 95 | 160 | } else { | 96 | 6 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 6 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 6 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 6 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 6 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 166 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 166 | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 166 | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 166 | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 160 | std::vector<uint32_t> high_accumulator; | 117 | 160 | if constexpr (HasPlookup<Builder>) { | 118 | 160 | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 160 | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 160 | limb_2.witness_index = limb_witnesses[0]; | 121 | 160 | limb_3.witness_index = limb_witnesses[1]; | 122 | 160 | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 160 | } else { | 125 | 160 | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 160 | static_cast<size_t>(num_high_limb_bits), | 127 | 160 | "bigfield: high_bits_in too large."); | 128 | | | 129 | 160 | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 160 | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 160 | } | 132 | 160 | } else { | 133 | 6 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 6 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 6 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 6 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 6 | } | 138 | 166 | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 166 | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 166 | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 166 | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 166 | } else { | 145 | 166 | binary_basis_limbs[3] = | 146 | 166 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 166 | } | 148 | 166 | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 166 | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 166 | set_origin_tag(new_tag); | 151 | 166 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm Line | Count | Source | 49 | 72 | { | 50 | 72 | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 72 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 72 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 72 | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 72 | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 72 | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 72 | field_t<Builder> limb_0(context); | 60 | 72 | field_t<Builder> limb_1(context); | 61 | 72 | field_t<Builder> limb_2(context); | 62 | 72 | field_t<Builder> limb_3(context); | 63 | 72 | if (!low_bits_in.is_constant()) { | 64 | 60 | std::vector<uint32_t> low_accumulator; | 65 | 60 | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 60 | const auto limb_witnesses = | 68 | 60 | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 60 | limb_0.witness_index = limb_witnesses[0]; | 70 | 60 | limb_1.witness_index = limb_witnesses[1]; | 71 | 60 | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 60 | } else { | 84 | 60 | size_t mid_index; | 85 | 60 | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 60 | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 60 | "bigfield: low_bits_in too large."); | 88 | 60 | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 60 | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 60 | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 60 | } | 95 | 60 | } else { | 96 | 12 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 12 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 12 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 12 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 12 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 72 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 72 | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 72 | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 72 | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 60 | std::vector<uint32_t> high_accumulator; | 117 | 60 | if constexpr (HasPlookup<Builder>) { | 118 | 60 | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 60 | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 60 | limb_2.witness_index = limb_witnesses[0]; | 121 | 60 | limb_3.witness_index = limb_witnesses[1]; | 122 | 60 | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 60 | } else { | 125 | 60 | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 60 | static_cast<size_t>(num_high_limb_bits), | 127 | 60 | "bigfield: high_bits_in too large."); | 128 | | | 129 | 60 | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 60 | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 60 | } | 132 | 60 | } else { | 133 | 12 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 12 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 12 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 12 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 12 | } | 138 | 72 | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 72 | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 72 | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 72 | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 72 | } else { | 145 | 72 | binary_basis_limbs[3] = | 146 | 72 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 72 | } | 148 | 72 | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 72 | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 72 | set_origin_tag(new_tag); | 151 | 72 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm Line | Count | Source | 49 | 3.74k | { | 50 | 3.74k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 3.74k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 3.74k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 3.74k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 3.74k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 3.74k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 3.74k | field_t<Builder> limb_0(context); | 60 | 3.74k | field_t<Builder> limb_1(context); | 61 | 3.74k | field_t<Builder> limb_2(context); | 62 | 3.74k | field_t<Builder> limb_3(context); | 63 | 3.74k | if (!low_bits_in.is_constant()) { | 64 | 3.60k | std::vector<uint32_t> low_accumulator; | 65 | 3.60k | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 3.60k | const auto limb_witnesses = | 68 | 3.60k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 3.60k | limb_0.witness_index = limb_witnesses[0]; | 70 | 3.60k | limb_1.witness_index = limb_witnesses[1]; | 71 | 3.60k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 3.60k | } else { | 84 | 3.60k | size_t mid_index; | 85 | 3.60k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 3.60k | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 3.60k | "bigfield: low_bits_in too large."); | 88 | 3.60k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 3.60k | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 3.60k | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 3.60k | } | 95 | 3.60k | } else { | 96 | 144 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 144 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 144 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 144 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 144 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 3.74k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 3.74k | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 3.74k | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 3.74k | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 3.60k | std::vector<uint32_t> high_accumulator; | 117 | 3.60k | if constexpr (HasPlookup<Builder>) { | 118 | 3.60k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 3.60k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 3.60k | limb_2.witness_index = limb_witnesses[0]; | 121 | 3.60k | limb_3.witness_index = limb_witnesses[1]; | 122 | 3.60k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 3.60k | } else { | 125 | 3.60k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 3.60k | static_cast<size_t>(num_high_limb_bits), | 127 | 3.60k | "bigfield: high_bits_in too large."); | 128 | | | 129 | 3.60k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 3.60k | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 3.60k | } | 132 | 3.60k | } else { | 133 | 144 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 144 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 144 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 144 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 144 | } | 138 | 3.74k | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 3.74k | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 3.74k | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 3.74k | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 3.74k | } else { | 145 | 3.74k | binary_basis_limbs[3] = | 146 | 3.74k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 3.74k | } | 148 | 3.74k | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 3.74k | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 3.74k | set_origin_tag(new_tag); | 151 | 3.74k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm Line | Count | Source | 49 | 1.44k | { | 50 | 1.44k | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 1.44k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 1.44k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 1.44k | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 1.44k | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 1.44k | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 1.44k | field_t<Builder> limb_0(context); | 60 | 1.44k | field_t<Builder> limb_1(context); | 61 | 1.44k | field_t<Builder> limb_2(context); | 62 | 1.44k | field_t<Builder> limb_3(context); | 63 | 1.44k | if (!low_bits_in.is_constant()) { | 64 | 1.15k | std::vector<uint32_t> low_accumulator; | 65 | 1.15k | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 1.15k | const auto limb_witnesses = | 68 | 1.15k | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 1.15k | limb_0.witness_index = limb_witnesses[0]; | 70 | 1.15k | limb_1.witness_index = limb_witnesses[1]; | 71 | 1.15k | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 1.15k | } else { | 84 | 1.15k | size_t mid_index; | 85 | 1.15k | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 1.15k | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 1.15k | "bigfield: low_bits_in too large."); | 88 | 1.15k | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 1.15k | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 1.15k | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 1.15k | } | 95 | 1.15k | } else { | 96 | 288 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 288 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 288 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 288 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 288 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 1.44k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 1.44k | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 1.44k | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 1.44k | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 1.15k | std::vector<uint32_t> high_accumulator; | 117 | 1.15k | if constexpr (HasPlookup<Builder>) { | 118 | 1.15k | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 1.15k | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 1.15k | limb_2.witness_index = limb_witnesses[0]; | 121 | 1.15k | limb_3.witness_index = limb_witnesses[1]; | 122 | 1.15k | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 1.15k | } else { | 125 | 1.15k | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 1.15k | static_cast<size_t>(num_high_limb_bits), | 127 | 1.15k | "bigfield: high_bits_in too large."); | 128 | | | 129 | 1.15k | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 1.15k | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 1.15k | } | 132 | 1.15k | } else { | 133 | 288 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 288 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 288 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 288 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 288 | } | 138 | 1.44k | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 1.44k | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 1.44k | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 1.44k | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 1.44k | } else { | 145 | 1.44k | binary_basis_limbs[3] = | 146 | 1.44k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 1.44k | } | 148 | 1.44k | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 1.44k | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 1.44k | set_origin_tag(new_tag); | 151 | 1.44k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm Line | Count | Source | 49 | 45 | { | 50 | 45 | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 45 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 45 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 45 | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 45 | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 45 | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 45 | field_t<Builder> limb_0(context); | 60 | 45 | field_t<Builder> limb_1(context); | 61 | 45 | field_t<Builder> limb_2(context); | 62 | 45 | field_t<Builder> limb_3(context); | 63 | 45 | if (!low_bits_in.is_constant()) { | 64 | 45 | std::vector<uint32_t> low_accumulator; | 65 | 45 | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 45 | const auto limb_witnesses = | 68 | 45 | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 45 | limb_0.witness_index = limb_witnesses[0]; | 70 | 45 | limb_1.witness_index = limb_witnesses[1]; | 71 | 45 | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 45 | } else { | 84 | 45 | size_t mid_index; | 85 | 45 | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 45 | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 45 | "bigfield: low_bits_in too large."); | 88 | 45 | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 45 | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 45 | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 45 | } | 95 | 45 | } else { | 96 | 0 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 0 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 0 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 0 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 0 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 45 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 45 | if (maximum_bitlength > 0) { | 109 | 0 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 0 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 45 | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 45 | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 45 | std::vector<uint32_t> high_accumulator; | 117 | 45 | if constexpr (HasPlookup<Builder>) { | 118 | 45 | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 45 | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 45 | limb_2.witness_index = limb_witnesses[0]; | 121 | 45 | limb_3.witness_index = limb_witnesses[1]; | 122 | 45 | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 45 | } else { | 125 | 45 | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 45 | static_cast<size_t>(num_high_limb_bits), | 127 | 45 | "bigfield: high_bits_in too large."); | 128 | | | 129 | 45 | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 45 | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 45 | } | 132 | 45 | } else { | 133 | 0 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 0 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 0 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 0 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 0 | } | 138 | 45 | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 45 | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 45 | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 45 | if (maximum_bitlength > 0) { | 142 | 0 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 0 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 45 | } else { | 145 | 45 | binary_basis_limbs[3] = | 146 | 45 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 45 | } | 148 | 45 | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 45 | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 45 | set_origin_tag(new_tag); | 151 | 45 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm Line | Count | Source | 49 | 50 | { | 50 | 50 | ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant()); | 51 | 50 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 52 | 50 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 53 | | | 54 | | // Check that the values of two parts are within specified bounds | 55 | 50 | ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 56 | 50 | ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); | 57 | | | 58 | 50 | context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context; | 59 | 50 | field_t<Builder> limb_0(context); | 60 | 50 | field_t<Builder> limb_1(context); | 61 | 50 | field_t<Builder> limb_2(context); | 62 | 50 | field_t<Builder> limb_3(context); | 63 | 50 | if (!low_bits_in.is_constant()) { | 64 | 50 | std::vector<uint32_t> low_accumulator; | 65 | 50 | if constexpr (HasPlookup<Builder>) { | 66 | | // MERGE NOTE: this was the if constexpr block introduced in ecebe7643 | 67 | 50 | const auto limb_witnesses = | 68 | 50 | context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index()); | 69 | 50 | limb_0.witness_index = limb_witnesses[0]; | 70 | 50 | limb_1.witness_index = limb_witnesses[1]; | 71 | 50 | field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0)); | 72 | | | 73 | | // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits | 74 | | // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index, | 75 | | // static_cast<size_t>(NUM_LIMB_BITS * 2)); | 76 | | // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb | 77 | | // size | 78 | | // // here | 79 | | // ASSERT(low_accumulator.size() % 2 == 0); | 80 | | // size_t mid_index = low_accumulator.size() / 2 - 1; | 81 | | // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in? | 82 | | // limb_1 = (low_bits_in - limb_0) * shift_right_1; | 83 | 50 | } else { | 84 | 50 | size_t mid_index; | 85 | 50 | low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(), | 86 | 50 | static_cast<size_t>(NUM_LIMB_BITS * 2), | 87 | 50 | "bigfield: low_bits_in too large."); | 88 | 50 | mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1); | 89 | | // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb | 90 | | // value | 91 | 50 | limb_1.witness_index = low_accumulator[mid_index]; | 92 | | // We can get the first half bits of low_bits_in from the variables we already created | 93 | 50 | limb_0 = (low_bits_in - (limb_1 * shift_1)); | 94 | 50 | } | 95 | 50 | } else { | 96 | 0 | uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 97 | 0 | uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); | 98 | 0 | limb_0 = field_t(context, bb::fr(slice_0)); | 99 | 0 | limb_1 = field_t(context, bb::fr(slice_1)); | 100 | 0 | } | 101 | | | 102 | | // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each | 103 | | // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow == | 104 | | // false) | 105 | 50 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 106 | | | 107 | | // if maximum_bitlength is set, this supercedes can_overflow | 108 | 50 | if (maximum_bitlength > 0) { | 109 | 10 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 110 | 10 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 111 | 10 | } | 112 | | // We create the high limb values similar to the low limb ones above | 113 | 50 | const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits; | 114 | 50 | if (!high_bits_in.is_constant()) { | 115 | | | 116 | 50 | std::vector<uint32_t> high_accumulator; | 117 | 50 | if constexpr (HasPlookup<Builder>) { | 118 | 50 | const auto limb_witnesses = context->decompose_non_native_field_double_width_limb( | 119 | 50 | high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits); | 120 | 50 | limb_2.witness_index = limb_witnesses[0]; | 121 | 50 | limb_3.witness_index = limb_witnesses[1]; | 122 | 50 | field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0)); | 123 | | | 124 | 50 | } else { | 125 | 50 | high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(), | 126 | 50 | static_cast<size_t>(num_high_limb_bits), | 127 | 50 | "bigfield: high_bits_in too large."); | 128 | | | 129 | 50 | limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)]; | 130 | 50 | limb_2 = (high_bits_in - (limb_3 * shift_1)); | 131 | 50 | } | 132 | 50 | } else { | 133 | 0 | uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); | 134 | 0 | uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); | 135 | 0 | limb_2 = field_t(context, bb::fr(slice_2)); | 136 | 0 | limb_3 = field_t(context, bb::fr(slice_3)); | 137 | 0 | } | 138 | 50 | binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 139 | 50 | binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 140 | 50 | binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 141 | 50 | if (maximum_bitlength > 0) { | 142 | 10 | uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1; | 143 | 10 | binary_basis_limbs[3] = Limb(limb_3, max_limb_value); | 144 | 40 | } else { | 145 | 40 | binary_basis_limbs[3] = | 146 | 40 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 147 | 40 | } | 148 | 50 | prime_basis_limb = low_bits_in + (high_bits_in * shift_2); | 149 | 50 | auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag); | 150 | 50 | set_origin_tag(new_tag); | 151 | 50 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm |
152 | | |
153 | | template <typename Builder, typename T> |
154 | | bigfield<Builder, T>::bigfield(const bigfield& other) |
155 | | : context(other.context) |
156 | | , binary_basis_limbs{ other.binary_basis_limbs[0], |
157 | | other.binary_basis_limbs[1], |
158 | | other.binary_basis_limbs[2], |
159 | | other.binary_basis_limbs[3] } |
160 | | , prime_basis_limb(other.prime_basis_limb) |
161 | 23.9M | {}_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKS6_ Line | Count | Source | 161 | 21.9M | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKS6_ Line | Count | Source | 161 | 3.42k | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKS8_ Line | Count | Source | 161 | 110 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKS7_ Line | Count | Source | 161 | 79.2k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKS7_ Line | Count | Source | 161 | 520 | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKS9_ Line | Count | Source | 161 | 1.75M | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKS9_ Line | Count | Source | 161 | 9.50k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKS7_ Line | Count | Source | 161 | 152k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKS7_ Line | Count | Source | 161 | 335 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKS9_ |
162 | | |
163 | | template <typename Builder, typename T> |
164 | | bigfield<Builder, T>::bigfield(bigfield&& other) |
165 | | : context(other.context) |
166 | | , binary_basis_limbs{ other.binary_basis_limbs[0], |
167 | | other.binary_basis_limbs[1], |
168 | | other.binary_basis_limbs[2], |
169 | | other.binary_basis_limbs[3] } |
170 | | , prime_basis_limb(other.prime_basis_limb) |
171 | 1.22M | {}_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EOS6_ Line | Count | Source | 171 | 1.12M | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EOS6_ Line | Count | Source | 171 | 788 | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EOS8_ Line | Count | Source | 171 | 20 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EOS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EOS7_ Line | Count | Source | 171 | 3.56k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EOS7_ Line | Count | Source | 171 | 123 | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EOS9_ Line | Count | Source | 171 | 77.7k | {} |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EOS9_ Line | Count | Source | 171 | 2.59k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EOS7_ Line | Count | Source | 171 | 11.3k | {} |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EOS7_ Line | Count | Source | 171 | 50 | {} |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EOS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EOS9_ |
172 | | |
173 | | /** |
174 | | * @brief Creates a bigfield element from a uint512_t. |
175 | | * Bigfield element is constructed as a witness and not a circuit constant |
176 | | * |
177 | | * @param ctx |
178 | | * @param value |
179 | | * @param can_overflow Can the input value have more than log2(modulus) bits? |
180 | | * @param maximum_bitlength Provide the explicit maximum bitlength if known. Otherwise bigfield max value will be |
181 | | * either log2(modulus) bits iff can_overflow = false, or (4 * NUM_LIMB_BITS) iff can_overflow = true |
182 | | * @return bigfield<Builder, T> |
183 | | * |
184 | | * @details This method is 1 gate more efficient than constructing from 2 field_ct elements. |
185 | | */ |
186 | | template <typename Builder, typename T> |
187 | | bigfield<Builder, T> bigfield<Builder, T>::create_from_u512_as_witness(Builder* ctx, |
188 | | const uint512_t& value, |
189 | | const bool can_overflow, |
190 | | const size_t maximum_bitlength) |
191 | 2.41M | { |
192 | 2.41M | ASSERT((can_overflow == true && maximum_bitlength == 0) || |
193 | 2.41M | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); |
194 | 0 | std::array<uint256_t, 4> limbs; |
195 | 0 | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; |
196 | 0 | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; |
197 | 0 | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; |
198 | 0 | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; |
199 | |
|
200 | 2.41M | if constexpr (HasPlookup<Builder>) { |
201 | 2.41M | field_t<Builder> limb_0(ctx); |
202 | 2.41M | field_t<Builder> limb_1(ctx); |
203 | 2.41M | field_t<Builder> limb_2(ctx); |
204 | 2.41M | field_t<Builder> limb_3(ctx); |
205 | 2.41M | field_t<Builder> prime_limb(ctx); |
206 | 2.41M | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); |
207 | 2.41M | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); |
208 | 2.41M | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); |
209 | 2.41M | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); |
210 | 2.41M | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + |
211 | 2.41M | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); |
212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate |
213 | 2.41M | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), |
214 | 2.41M | limb_2.get_normalized_witness_index(), |
215 | 2.41M | limb_3.get_normalized_witness_index(), |
216 | 2.41M | prime_limb.get_normalized_witness_index(), |
217 | 2.41M | shift_1, |
218 | 2.41M | shift_2, |
219 | 2.41M | shift_3, |
220 | 2.41M | -1, |
221 | 2.41M | 0 }, |
222 | 2.41M | true); |
223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add |
224 | | // gate |
225 | 2.41M | ctx->create_dummy_gate( |
226 | 2.41M | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); |
227 | | |
228 | 2.41M | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; |
229 | | |
230 | 2.41M | bigfield result(ctx); |
231 | 2.41M | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); |
232 | 2.41M | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); |
233 | 2.41M | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); |
234 | 2.41M | result.binary_basis_limbs[3] = |
235 | 2.41M | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); |
236 | | |
237 | | // if maximum_bitlength is set, this supercedes can_overflow |
238 | 2.41M | if (maximum_bitlength > 0) { |
239 | 1.20M | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); |
240 | 0 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); |
241 | 0 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; |
242 | 0 | result.binary_basis_limbs[3].maximum_value = max_limb_value; |
243 | 0 | } |
244 | 0 | result.prime_basis_limb = prime_limb; |
245 | 0 | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), |
246 | 0 | limb_1.get_normalized_witness_index(), |
247 | 0 | (size_t)NUM_LIMB_BITS, |
248 | 0 | (size_t)NUM_LIMB_BITS); |
249 | 0 | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), |
250 | 0 | limb_3.get_normalized_witness_index(), |
251 | 0 | (size_t)NUM_LIMB_BITS, |
252 | 0 | (size_t)num_last_limb_bits); |
253 | |
|
254 | 0 | return result; |
255 | 2.41M | } else { |
256 | 0 | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), |
257 | 0 | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), |
258 | 0 | can_overflow, |
259 | 0 | maximum_bitlength); |
260 | 0 | } |
261 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm Line | Count | Source | 191 | 2.21M | { | 192 | 2.21M | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 2.21M | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 2.21M | std::array<uint256_t, 4> limbs; | 195 | 2.21M | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 2.21M | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 2.21M | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 2.21M | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 2.21M | if constexpr (HasPlookup<Builder>) { | 201 | 2.21M | field_t<Builder> limb_0(ctx); | 202 | 2.21M | field_t<Builder> limb_1(ctx); | 203 | 2.21M | field_t<Builder> limb_2(ctx); | 204 | 2.21M | field_t<Builder> limb_3(ctx); | 205 | 2.21M | field_t<Builder> prime_limb(ctx); | 206 | 2.21M | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 2.21M | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 2.21M | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 2.21M | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 2.21M | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 2.21M | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 2.21M | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 2.21M | limb_2.get_normalized_witness_index(), | 215 | 2.21M | limb_3.get_normalized_witness_index(), | 216 | 2.21M | prime_limb.get_normalized_witness_index(), | 217 | 2.21M | shift_1, | 218 | 2.21M | shift_2, | 219 | 2.21M | shift_3, | 220 | 2.21M | -1, | 221 | 2.21M | 0 }, | 222 | 2.21M | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 2.21M | ctx->create_dummy_gate( | 226 | 2.21M | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 2.21M | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 2.21M | bigfield result(ctx); | 231 | 2.21M | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 2.21M | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 2.21M | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 2.21M | result.binary_basis_limbs[3] = | 235 | 2.21M | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 2.21M | if (maximum_bitlength > 0) { | 239 | 1.10M | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 1.10M | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 1.10M | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 1.10M | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 1.10M | } | 244 | 2.21M | result.prime_basis_limb = prime_limb; | 245 | 2.21M | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 2.21M | limb_1.get_normalized_witness_index(), | 247 | 2.21M | (size_t)NUM_LIMB_BITS, | 248 | 2.21M | (size_t)NUM_LIMB_BITS); | 249 | 2.21M | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 2.21M | limb_3.get_normalized_witness_index(), | 251 | 2.21M | (size_t)NUM_LIMB_BITS, | 252 | 2.21M | (size_t)num_last_limb_bits); | 253 | | | 254 | 2.21M | return result; | 255 | 2.21M | } else { | 256 | 2.21M | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 2.21M | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 2.21M | can_overflow, | 259 | 2.21M | maximum_bitlength); | 260 | 2.21M | } | 261 | 2.21M | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm Line | Count | Source | 191 | 76 | { | 192 | 76 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 76 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 76 | std::array<uint256_t, 4> limbs; | 195 | 76 | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 76 | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 76 | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 76 | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 76 | if constexpr (HasPlookup<Builder>) { | 201 | 76 | field_t<Builder> limb_0(ctx); | 202 | 76 | field_t<Builder> limb_1(ctx); | 203 | 76 | field_t<Builder> limb_2(ctx); | 204 | 76 | field_t<Builder> limb_3(ctx); | 205 | 76 | field_t<Builder> prime_limb(ctx); | 206 | 76 | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 76 | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 76 | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 76 | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 76 | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 76 | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 76 | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 76 | limb_2.get_normalized_witness_index(), | 215 | 76 | limb_3.get_normalized_witness_index(), | 216 | 76 | prime_limb.get_normalized_witness_index(), | 217 | 76 | shift_1, | 218 | 76 | shift_2, | 219 | 76 | shift_3, | 220 | 76 | -1, | 221 | 76 | 0 }, | 222 | 76 | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 76 | ctx->create_dummy_gate( | 226 | 76 | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 76 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 76 | bigfield result(ctx); | 231 | 76 | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 76 | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 76 | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 76 | result.binary_basis_limbs[3] = | 235 | 76 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 76 | if (maximum_bitlength > 0) { | 239 | 38 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 38 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 38 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 38 | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 38 | } | 244 | 76 | result.prime_basis_limb = prime_limb; | 245 | 76 | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 76 | limb_1.get_normalized_witness_index(), | 247 | 76 | (size_t)NUM_LIMB_BITS, | 248 | 76 | (size_t)NUM_LIMB_BITS); | 249 | 76 | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 76 | limb_3.get_normalized_witness_index(), | 251 | 76 | (size_t)NUM_LIMB_BITS, | 252 | 76 | (size_t)num_last_limb_bits); | 253 | | | 254 | 76 | return result; | 255 | 76 | } else { | 256 | 76 | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 76 | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 76 | can_overflow, | 259 | 76 | maximum_bitlength); | 260 | 76 | } | 261 | 76 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm Line | Count | Source | 191 | 32 | { | 192 | 32 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 32 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 32 | std::array<uint256_t, 4> limbs; | 195 | 32 | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 32 | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 32 | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 32 | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 32 | if constexpr (HasPlookup<Builder>) { | 201 | 32 | field_t<Builder> limb_0(ctx); | 202 | 32 | field_t<Builder> limb_1(ctx); | 203 | 32 | field_t<Builder> limb_2(ctx); | 204 | 32 | field_t<Builder> limb_3(ctx); | 205 | 32 | field_t<Builder> prime_limb(ctx); | 206 | 32 | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 32 | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 32 | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 32 | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 32 | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 32 | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 32 | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 32 | limb_2.get_normalized_witness_index(), | 215 | 32 | limb_3.get_normalized_witness_index(), | 216 | 32 | prime_limb.get_normalized_witness_index(), | 217 | 32 | shift_1, | 218 | 32 | shift_2, | 219 | 32 | shift_3, | 220 | 32 | -1, | 221 | 32 | 0 }, | 222 | 32 | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 32 | ctx->create_dummy_gate( | 226 | 32 | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 32 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 32 | bigfield result(ctx); | 231 | 32 | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 32 | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 32 | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 32 | result.binary_basis_limbs[3] = | 235 | 32 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 32 | if (maximum_bitlength > 0) { | 239 | 16 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 16 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 16 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 16 | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 16 | } | 244 | 32 | result.prime_basis_limb = prime_limb; | 245 | 32 | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 32 | limb_1.get_normalized_witness_index(), | 247 | 32 | (size_t)NUM_LIMB_BITS, | 248 | 32 | (size_t)NUM_LIMB_BITS); | 249 | 32 | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 32 | limb_3.get_normalized_witness_index(), | 251 | 32 | (size_t)NUM_LIMB_BITS, | 252 | 32 | (size_t)num_last_limb_bits); | 253 | | | 254 | 32 | return result; | 255 | 32 | } else { | 256 | 32 | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 32 | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 32 | can_overflow, | 259 | 32 | maximum_bitlength); | 260 | 32 | } | 261 | 32 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm Line | Count | Source | 191 | 8.01k | { | 192 | 8.01k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 8.01k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 8.01k | std::array<uint256_t, 4> limbs; | 195 | 8.01k | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 8.01k | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 8.01k | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 8.01k | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 8.01k | if constexpr (HasPlookup<Builder>) { | 201 | 8.01k | field_t<Builder> limb_0(ctx); | 202 | 8.01k | field_t<Builder> limb_1(ctx); | 203 | 8.01k | field_t<Builder> limb_2(ctx); | 204 | 8.01k | field_t<Builder> limb_3(ctx); | 205 | 8.01k | field_t<Builder> prime_limb(ctx); | 206 | 8.01k | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 8.01k | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 8.01k | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 8.01k | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 8.01k | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 8.01k | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 8.01k | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 8.01k | limb_2.get_normalized_witness_index(), | 215 | 8.01k | limb_3.get_normalized_witness_index(), | 216 | 8.01k | prime_limb.get_normalized_witness_index(), | 217 | 8.01k | shift_1, | 218 | 8.01k | shift_2, | 219 | 8.01k | shift_3, | 220 | 8.01k | -1, | 221 | 8.01k | 0 }, | 222 | 8.01k | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 8.01k | ctx->create_dummy_gate( | 226 | 8.01k | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 8.01k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 8.01k | bigfield result(ctx); | 231 | 8.01k | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 8.01k | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 8.01k | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 8.01k | result.binary_basis_limbs[3] = | 235 | 8.01k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 8.01k | if (maximum_bitlength > 0) { | 239 | 4.01k | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 4.01k | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 4.01k | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 4.01k | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 4.01k | } | 244 | 8.01k | result.prime_basis_limb = prime_limb; | 245 | 8.01k | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 8.01k | limb_1.get_normalized_witness_index(), | 247 | 8.01k | (size_t)NUM_LIMB_BITS, | 248 | 8.01k | (size_t)NUM_LIMB_BITS); | 249 | 8.01k | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 8.01k | limb_3.get_normalized_witness_index(), | 251 | 8.01k | (size_t)NUM_LIMB_BITS, | 252 | 8.01k | (size_t)num_last_limb_bits); | 253 | | | 254 | 8.01k | return result; | 255 | 8.01k | } else { | 256 | 8.01k | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 8.01k | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 8.01k | can_overflow, | 259 | 8.01k | maximum_bitlength); | 260 | 8.01k | } | 261 | 8.01k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm Line | Count | Source | 191 | 54 | { | 192 | 54 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 54 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 54 | std::array<uint256_t, 4> limbs; | 195 | 54 | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 54 | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 54 | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 54 | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 54 | if constexpr (HasPlookup<Builder>) { | 201 | 54 | field_t<Builder> limb_0(ctx); | 202 | 54 | field_t<Builder> limb_1(ctx); | 203 | 54 | field_t<Builder> limb_2(ctx); | 204 | 54 | field_t<Builder> limb_3(ctx); | 205 | 54 | field_t<Builder> prime_limb(ctx); | 206 | 54 | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 54 | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 54 | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 54 | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 54 | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 54 | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 54 | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 54 | limb_2.get_normalized_witness_index(), | 215 | 54 | limb_3.get_normalized_witness_index(), | 216 | 54 | prime_limb.get_normalized_witness_index(), | 217 | 54 | shift_1, | 218 | 54 | shift_2, | 219 | 54 | shift_3, | 220 | 54 | -1, | 221 | 54 | 0 }, | 222 | 54 | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 54 | ctx->create_dummy_gate( | 226 | 54 | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 54 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 54 | bigfield result(ctx); | 231 | 54 | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 54 | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 54 | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 54 | result.binary_basis_limbs[3] = | 235 | 54 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 54 | if (maximum_bitlength > 0) { | 239 | 27 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 27 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 27 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 27 | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 27 | } | 244 | 54 | result.prime_basis_limb = prime_limb; | 245 | 54 | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 54 | limb_1.get_normalized_witness_index(), | 247 | 54 | (size_t)NUM_LIMB_BITS, | 248 | 54 | (size_t)NUM_LIMB_BITS); | 249 | 54 | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 54 | limb_3.get_normalized_witness_index(), | 251 | 54 | (size_t)NUM_LIMB_BITS, | 252 | 54 | (size_t)num_last_limb_bits); | 253 | | | 254 | 54 | return result; | 255 | 54 | } else { | 256 | 54 | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 54 | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 54 | can_overflow, | 259 | 54 | maximum_bitlength); | 260 | 54 | } | 261 | 54 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm Line | Count | Source | 191 | 172k | { | 192 | 172k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 172k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 172k | std::array<uint256_t, 4> limbs; | 195 | 172k | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 172k | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 172k | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 172k | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 172k | if constexpr (HasPlookup<Builder>) { | 201 | 172k | field_t<Builder> limb_0(ctx); | 202 | 172k | field_t<Builder> limb_1(ctx); | 203 | 172k | field_t<Builder> limb_2(ctx); | 204 | 172k | field_t<Builder> limb_3(ctx); | 205 | 172k | field_t<Builder> prime_limb(ctx); | 206 | 172k | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 172k | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 172k | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 172k | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 172k | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 172k | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 172k | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 172k | limb_2.get_normalized_witness_index(), | 215 | 172k | limb_3.get_normalized_witness_index(), | 216 | 172k | prime_limb.get_normalized_witness_index(), | 217 | 172k | shift_1, | 218 | 172k | shift_2, | 219 | 172k | shift_3, | 220 | 172k | -1, | 221 | 172k | 0 }, | 222 | 172k | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 172k | ctx->create_dummy_gate( | 226 | 172k | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 172k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 172k | bigfield result(ctx); | 231 | 172k | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 172k | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 172k | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 172k | result.binary_basis_limbs[3] = | 235 | 172k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 172k | if (maximum_bitlength > 0) { | 239 | 86.4k | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 86.4k | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 86.4k | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 86.4k | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 86.4k | } | 244 | 172k | result.prime_basis_limb = prime_limb; | 245 | 172k | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 172k | limb_1.get_normalized_witness_index(), | 247 | 172k | (size_t)NUM_LIMB_BITS, | 248 | 172k | (size_t)NUM_LIMB_BITS); | 249 | 172k | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 172k | limb_3.get_normalized_witness_index(), | 251 | 172k | (size_t)NUM_LIMB_BITS, | 252 | 172k | (size_t)num_last_limb_bits); | 253 | | | 254 | 172k | return result; | 255 | 172k | } else { | 256 | 172k | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 172k | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 172k | can_overflow, | 259 | 172k | maximum_bitlength); | 260 | 172k | } | 261 | 172k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm Line | Count | Source | 191 | 1.15k | { | 192 | 1.15k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 1.15k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 1.15k | std::array<uint256_t, 4> limbs; | 195 | 1.15k | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 1.15k | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 1.15k | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 1.15k | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 1.15k | if constexpr (HasPlookup<Builder>) { | 201 | 1.15k | field_t<Builder> limb_0(ctx); | 202 | 1.15k | field_t<Builder> limb_1(ctx); | 203 | 1.15k | field_t<Builder> limb_2(ctx); | 204 | 1.15k | field_t<Builder> limb_3(ctx); | 205 | 1.15k | field_t<Builder> prime_limb(ctx); | 206 | 1.15k | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 1.15k | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 1.15k | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 1.15k | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 1.15k | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 1.15k | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 1.15k | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 1.15k | limb_2.get_normalized_witness_index(), | 215 | 1.15k | limb_3.get_normalized_witness_index(), | 216 | 1.15k | prime_limb.get_normalized_witness_index(), | 217 | 1.15k | shift_1, | 218 | 1.15k | shift_2, | 219 | 1.15k | shift_3, | 220 | 1.15k | -1, | 221 | 1.15k | 0 }, | 222 | 1.15k | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 1.15k | ctx->create_dummy_gate( | 226 | 1.15k | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 1.15k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 1.15k | bigfield result(ctx); | 231 | 1.15k | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 1.15k | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 1.15k | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 1.15k | result.binary_basis_limbs[3] = | 235 | 1.15k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 1.15k | if (maximum_bitlength > 0) { | 239 | 576 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 576 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 576 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 576 | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 576 | } | 244 | 1.15k | result.prime_basis_limb = prime_limb; | 245 | 1.15k | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 1.15k | limb_1.get_normalized_witness_index(), | 247 | 1.15k | (size_t)NUM_LIMB_BITS, | 248 | 1.15k | (size_t)NUM_LIMB_BITS); | 249 | 1.15k | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 1.15k | limb_3.get_normalized_witness_index(), | 251 | 1.15k | (size_t)NUM_LIMB_BITS, | 252 | 1.15k | (size_t)num_last_limb_bits); | 253 | | | 254 | 1.15k | return result; | 255 | 1.15k | } else { | 256 | 1.15k | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 1.15k | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 1.15k | can_overflow, | 259 | 1.15k | maximum_bitlength); | 260 | 1.15k | } | 261 | 1.15k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm Line | Count | Source | 191 | 11.1k | { | 192 | 11.1k | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 11.1k | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 11.1k | std::array<uint256_t, 4> limbs; | 195 | 11.1k | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 11.1k | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 11.1k | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 11.1k | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 11.1k | if constexpr (HasPlookup<Builder>) { | 201 | 11.1k | field_t<Builder> limb_0(ctx); | 202 | 11.1k | field_t<Builder> limb_1(ctx); | 203 | 11.1k | field_t<Builder> limb_2(ctx); | 204 | 11.1k | field_t<Builder> limb_3(ctx); | 205 | 11.1k | field_t<Builder> prime_limb(ctx); | 206 | 11.1k | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 11.1k | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 11.1k | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 11.1k | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 11.1k | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 11.1k | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 11.1k | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 11.1k | limb_2.get_normalized_witness_index(), | 215 | 11.1k | limb_3.get_normalized_witness_index(), | 216 | 11.1k | prime_limb.get_normalized_witness_index(), | 217 | 11.1k | shift_1, | 218 | 11.1k | shift_2, | 219 | 11.1k | shift_3, | 220 | 11.1k | -1, | 221 | 11.1k | 0 }, | 222 | 11.1k | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 11.1k | ctx->create_dummy_gate( | 226 | 11.1k | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 11.1k | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 11.1k | bigfield result(ctx); | 231 | 11.1k | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 11.1k | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 11.1k | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 11.1k | result.binary_basis_limbs[3] = | 235 | 11.1k | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 11.1k | if (maximum_bitlength > 0) { | 239 | 5.56k | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 5.56k | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 5.56k | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 5.56k | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 5.56k | } | 244 | 11.1k | result.prime_basis_limb = prime_limb; | 245 | 11.1k | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 11.1k | limb_1.get_normalized_witness_index(), | 247 | 11.1k | (size_t)NUM_LIMB_BITS, | 248 | 11.1k | (size_t)NUM_LIMB_BITS); | 249 | 11.1k | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 11.1k | limb_3.get_normalized_witness_index(), | 251 | 11.1k | (size_t)NUM_LIMB_BITS, | 252 | 11.1k | (size_t)num_last_limb_bits); | 253 | | | 254 | 11.1k | return result; | 255 | 11.1k | } else { | 256 | 11.1k | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 11.1k | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 11.1k | can_overflow, | 259 | 11.1k | maximum_bitlength); | 260 | 11.1k | } | 261 | 11.1k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm Line | Count | Source | 191 | 20 | { | 192 | 20 | ASSERT((can_overflow == true && maximum_bitlength == 0) || | 193 | 20 | (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS)))); | 194 | 20 | std::array<uint256_t, 4> limbs; | 195 | 20 | limbs[0] = value.slice(0, NUM_LIMB_BITS).lo; | 196 | 20 | limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo; | 197 | 20 | limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo; | 198 | 20 | limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo; | 199 | | | 200 | 20 | if constexpr (HasPlookup<Builder>) { | 201 | 20 | field_t<Builder> limb_0(ctx); | 202 | 20 | field_t<Builder> limb_1(ctx); | 203 | 20 | field_t<Builder> limb_2(ctx); | 204 | 20 | field_t<Builder> limb_3(ctx); | 205 | 20 | field_t<Builder> prime_limb(ctx); | 206 | 20 | limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0])); | 207 | 20 | limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1])); | 208 | 20 | limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2])); | 209 | 20 | limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3])); | 210 | 20 | prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 + | 211 | 20 | limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3); | 212 | | // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate | 213 | 20 | ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(), | 214 | 20 | limb_2.get_normalized_witness_index(), | 215 | 20 | limb_3.get_normalized_witness_index(), | 216 | 20 | prime_limb.get_normalized_witness_index(), | 217 | 20 | shift_1, | 218 | 20 | shift_2, | 219 | 20 | shift_3, | 220 | 20 | -1, | 221 | 20 | 0 }, | 222 | 20 | true); | 223 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add | 224 | | // gate | 225 | 20 | ctx->create_dummy_gate( | 226 | 20 | ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index()); | 227 | | | 228 | 20 | uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; | 229 | | | 230 | 20 | bigfield result(ctx); | 231 | 20 | result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB); | 232 | 20 | result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB); | 233 | 20 | result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB); | 234 | 20 | result.binary_basis_limbs[3] = | 235 | 20 | Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB); | 236 | | | 237 | | // if maximum_bitlength is set, this supercedes can_overflow | 238 | 20 | if (maximum_bitlength > 0) { | 239 | 10 | ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS); | 240 | 10 | num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS); | 241 | 10 | uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1; | 242 | 10 | result.binary_basis_limbs[3].maximum_value = max_limb_value; | 243 | 10 | } | 244 | 20 | result.prime_basis_limb = prime_limb; | 245 | 20 | ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(), | 246 | 20 | limb_1.get_normalized_witness_index(), | 247 | 20 | (size_t)NUM_LIMB_BITS, | 248 | 20 | (size_t)NUM_LIMB_BITS); | 249 | 20 | ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(), | 250 | 20 | limb_3.get_normalized_witness_index(), | 251 | 20 | (size_t)NUM_LIMB_BITS, | 252 | 20 | (size_t)num_last_limb_bits); | 253 | | | 254 | 20 | return result; | 255 | 20 | } else { | 256 | 20 | return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)), | 257 | 20 | witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)), | 258 | 20 | can_overflow, | 259 | 20 | maximum_bitlength); | 260 | 20 | } | 261 | 20 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm |
262 | | |
263 | | template <typename Builder, typename T> bigfield<Builder, T>::bigfield(const byte_array<Builder>& bytes) |
264 | 520 | { |
265 | 520 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer |
266 | 1.04k | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { |
267 | 1.04k | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; |
268 | 1.04k | const uint64_t lo_nibble_val = byte_val & 15ULL; |
269 | 1.04k | const uint64_t hi_nibble_val = byte_val >> 4; |
270 | | |
271 | 1.04k | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); |
272 | 1.04k | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); |
273 | 1.04k | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); |
274 | 1.04k | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); |
275 | | |
276 | 1.04k | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); |
277 | 1.04k | sum.assert_equal(split_byte); |
278 | 1.04k | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, |
279 | 1.04k | (field_t<Builder>)hi_nibble); |
280 | 1.04k | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_ Line | Count | Source | 266 | 62 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 62 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 62 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 62 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 62 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 62 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 62 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 62 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 62 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 62 | sum.assert_equal(split_byte); | 278 | 62 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 62 | (field_t<Builder>)hi_nibble); | 280 | 62 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESD_SH_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESC_SG_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_ Line | Count | Source | 266 | 20 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 20 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 20 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 20 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 20 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 20 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 20 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 20 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 20 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 20 | sum.assert_equal(split_byte); | 278 | 20 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 20 | (field_t<Builder>)hi_nibble); | 280 | 20 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_ Line | Count | Source | 266 | 48 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 48 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 48 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 48 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 48 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 48 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 48 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 48 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 48 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 48 | sum.assert_equal(split_byte); | 278 | 48 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 48 | (field_t<Builder>)hi_nibble); | 280 | 48 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_ _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_ Line | Count | Source | 266 | 864 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 864 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 864 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 864 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 864 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 864 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 864 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 864 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 864 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 864 | sum.assert_equal(split_byte); | 278 | 864 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 864 | (field_t<Builder>)hi_nibble); | 280 | 864 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_ Line | Count | Source | 266 | 16 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 16 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 16 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 16 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 16 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 16 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 16 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 16 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 16 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 16 | sum.assert_equal(split_byte); | 278 | 16 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 16 | (field_t<Builder>)hi_nibble); | 280 | 16 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_ Line | Count | Source | 266 | 30 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 30 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 30 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 30 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 30 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 30 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 30 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 30 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 30 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 30 | sum.assert_equal(split_byte); | 278 | 30 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 30 | (field_t<Builder>)hi_nibble); | 280 | 30 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_ |
281 | |
|
282 | 0 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, |
283 | 0 | const field_t<Builder>& hi_bytes, |
284 | 0 | const field_t<Builder>& lo_bytes, |
285 | 1.04k | const field_t<Builder>& split_byte) { |
286 | 1.04k | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); |
287 | | |
288 | 1.04k | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; |
289 | 1.04k | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); |
290 | 1.04k | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); |
291 | 1.04k | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_ Line | Count | Source | 285 | 62 | const field_t<Builder>& split_byte) { | 286 | 62 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 62 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 62 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 62 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 62 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESH_SH_E_clESD_SH_SH_SH_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESG_SG_E_clESC_SG_SG_SG_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_ Line | Count | Source | 285 | 20 | const field_t<Builder>& split_byte) { | 286 | 20 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 20 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 20 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 20 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 20 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_ Line | Count | Source | 285 | 48 | const field_t<Builder>& split_byte) { | 286 | 48 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 48 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 48 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 48 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 48 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_ _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_ Line | Count | Source | 285 | 864 | const field_t<Builder>& split_byte) { | 286 | 864 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 864 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 864 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 864 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 864 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_ Line | Count | Source | 285 | 16 | const field_t<Builder>& split_byte) { | 286 | 16 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 16 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 16 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 16 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 16 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_ Line | Count | Source | 285 | 30 | const field_t<Builder>& split_byte) { | 286 | 30 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 30 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 30 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 30 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 30 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_ |
292 | 0 | Builder* ctx = bytes.get_context(); |
293 | |
|
294 | 0 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); |
295 | 0 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); |
296 | 0 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); |
297 | |
|
298 | 0 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); |
299 | 0 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); |
300 | 0 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); |
301 | |
|
302 | 0 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); |
303 | 0 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); |
304 | |
|
305 | 0 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); |
306 | |
|
307 | 0 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); |
308 | 0 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); |
309 | 0 | *this = res; |
310 | 0 | set_origin_tag(bytes.get_origin_tag()); |
311 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE Line | Count | Source | 264 | 31 | { | 265 | 31 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 31 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 31 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 31 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 31 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 31 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 31 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 31 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 31 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 31 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 31 | sum.assert_equal(split_byte); | 278 | 31 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 31 | (field_t<Builder>)hi_nibble); | 280 | 31 | }; | 281 | | | 282 | 31 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 31 | const field_t<Builder>& hi_bytes, | 284 | 31 | const field_t<Builder>& lo_bytes, | 285 | 31 | const field_t<Builder>& split_byte) { | 286 | 31 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 31 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 31 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 31 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 31 | }; | 292 | 31 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 31 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 31 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 31 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 31 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 31 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 31 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 31 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 31 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 31 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 31 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 31 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 31 | *this = res; | 310 | 31 | set_origin_tag(bytes.get_origin_tag()); | 311 | 31 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE Line | Count | Source | 264 | 10 | { | 265 | 10 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 10 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 10 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 10 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 10 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 10 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 10 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 10 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 10 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 10 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 10 | sum.assert_equal(split_byte); | 278 | 10 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 10 | (field_t<Builder>)hi_nibble); | 280 | 10 | }; | 281 | | | 282 | 10 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 10 | const field_t<Builder>& hi_bytes, | 284 | 10 | const field_t<Builder>& lo_bytes, | 285 | 10 | const field_t<Builder>& split_byte) { | 286 | 10 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 10 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 10 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 10 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 10 | }; | 292 | 10 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 10 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 10 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 10 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 10 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 10 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 10 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 10 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 10 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 10 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 10 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 10 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 10 | *this = res; | 310 | 10 | set_origin_tag(bytes.get_origin_tag()); | 311 | 10 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE Line | Count | Source | 264 | 24 | { | 265 | 24 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 24 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 24 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 24 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 24 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 24 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 24 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 24 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 24 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 24 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 24 | sum.assert_equal(split_byte); | 278 | 24 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 24 | (field_t<Builder>)hi_nibble); | 280 | 24 | }; | 281 | | | 282 | 24 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 24 | const field_t<Builder>& hi_bytes, | 284 | 24 | const field_t<Builder>& lo_bytes, | 285 | 24 | const field_t<Builder>& split_byte) { | 286 | 24 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 24 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 24 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 24 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 24 | }; | 292 | 24 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 24 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 24 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 24 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 24 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 24 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 24 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 24 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 24 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 24 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 24 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 24 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 24 | *this = res; | 310 | 24 | set_origin_tag(bytes.get_origin_tag()); | 311 | 24 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE Line | Count | Source | 264 | 432 | { | 265 | 432 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 432 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 432 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 432 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 432 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 432 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 432 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 432 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 432 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 432 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 432 | sum.assert_equal(split_byte); | 278 | 432 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 432 | (field_t<Builder>)hi_nibble); | 280 | 432 | }; | 281 | | | 282 | 432 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 432 | const field_t<Builder>& hi_bytes, | 284 | 432 | const field_t<Builder>& lo_bytes, | 285 | 432 | const field_t<Builder>& split_byte) { | 286 | 432 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 432 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 432 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 432 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 432 | }; | 292 | 432 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 432 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 432 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 432 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 432 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 432 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 432 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 432 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 432 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 432 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 432 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 432 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 432 | *this = res; | 310 | 432 | set_origin_tag(bytes.get_origin_tag()); | 311 | 432 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE Line | Count | Source | 264 | 8 | { | 265 | 8 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 8 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 8 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 8 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 8 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 8 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 8 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 8 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 8 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 8 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 8 | sum.assert_equal(split_byte); | 278 | 8 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 8 | (field_t<Builder>)hi_nibble); | 280 | 8 | }; | 281 | | | 282 | 8 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 8 | const field_t<Builder>& hi_bytes, | 284 | 8 | const field_t<Builder>& lo_bytes, | 285 | 8 | const field_t<Builder>& split_byte) { | 286 | 8 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 8 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 8 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 8 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 8 | }; | 292 | 8 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 8 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 8 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 8 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 8 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 8 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 8 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 8 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 8 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 8 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 8 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 8 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 8 | *this = res; | 310 | 8 | set_origin_tag(bytes.get_origin_tag()); | 311 | 8 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE Line | Count | Source | 264 | 15 | { | 265 | 15 | ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer | 266 | 15 | const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) { | 267 | 15 | const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0]; | 268 | 15 | const uint64_t lo_nibble_val = byte_val & 15ULL; | 269 | 15 | const uint64_t hi_nibble_val = byte_val >> 4; | 270 | | | 271 | 15 | const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val)); | 272 | 15 | const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val)); | 273 | 15 | lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large"); | 274 | 15 | hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large"); | 275 | | | 276 | 15 | const field_t<Builder> sum = lo_nibble + (hi_nibble * 16); | 277 | 15 | sum.assert_equal(split_byte); | 278 | 15 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble, | 279 | 15 | (field_t<Builder>)hi_nibble); | 280 | 15 | }; | 281 | | | 282 | 15 | const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx, | 283 | 15 | const field_t<Builder>& hi_bytes, | 284 | 15 | const field_t<Builder>& lo_bytes, | 285 | 15 | const field_t<Builder>& split_byte) { | 286 | 15 | const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte); | 287 | | | 288 | 15 | field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16; | 289 | 15 | field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64); | 290 | 15 | return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb); | 291 | 15 | }; | 292 | 15 | Builder* ctx = bytes.get_context(); | 293 | | | 294 | 15 | const field_t<Builder> hi_8_bytes(bytes.slice(0, 6)); | 295 | 15 | const field_t<Builder> mid_split_byte(bytes.slice(6, 1)); | 296 | 15 | const field_t<Builder> mid_8_bytes(bytes.slice(7, 8)); | 297 | | | 298 | 15 | const field_t<Builder> lo_8_bytes(bytes.slice(15, 8)); | 299 | 15 | const field_t<Builder> lo_split_byte(bytes.slice(23, 1)); | 300 | 15 | const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8)); | 301 | | | 302 | 15 | const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte); | 303 | 15 | const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte); | 304 | | | 305 | 15 | const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true); | 306 | | | 307 | 15 | const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3); | 308 | 15 | res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits); | 309 | 15 | *this = res; | 310 | 15 | set_origin_tag(bytes.get_origin_tag()); | 311 | 15 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE |
312 | | |
313 | | template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(const bigfield& other) |
314 | 1.83M | { |
315 | 1.83M | context = other.context; |
316 | 1.83M | binary_basis_limbs[0] = other.binary_basis_limbs[0]; |
317 | 1.83M | binary_basis_limbs[1] = other.binary_basis_limbs[1]; |
318 | 1.83M | binary_basis_limbs[2] = other.binary_basis_limbs[2]; |
319 | 1.83M | binary_basis_limbs[3] = other.binary_basis_limbs[3]; |
320 | 1.83M | prime_basis_limb = other.prime_basis_limb; |
321 | 1.83M | return *this; |
322 | 1.83M | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSERKS6_ Line | Count | Source | 314 | 1.74M | { | 315 | 1.74M | context = other.context; | 316 | 1.74M | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 1.74M | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 1.74M | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 1.74M | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 1.74M | prime_basis_limb = other.prime_basis_limb; | 321 | 1.74M | return *this; | 322 | 1.74M | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSERKS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSERKS8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSERKS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSERKS7_ Line | Count | Source | 314 | 3.64k | { | 315 | 3.64k | context = other.context; | 316 | 3.64k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 3.64k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 3.64k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 3.64k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 3.64k | prime_basis_limb = other.prime_basis_limb; | 321 | 3.64k | return *this; | 322 | 3.64k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSERKS7_ Line | Count | Source | 314 | 60 | { | 315 | 60 | context = other.context; | 316 | 60 | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 60 | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 60 | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 60 | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 60 | prime_basis_limb = other.prime_basis_limb; | 321 | 60 | return *this; | 322 | 60 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSERKS9_ Line | Count | Source | 314 | 80.9k | { | 315 | 80.9k | context = other.context; | 316 | 80.9k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 80.9k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 80.9k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 80.9k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 80.9k | prime_basis_limb = other.prime_basis_limb; | 321 | 80.9k | return *this; | 322 | 80.9k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSERKS9_ Line | Count | Source | 314 | 1.00k | { | 315 | 1.00k | context = other.context; | 316 | 1.00k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 1.00k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 1.00k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 1.00k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 1.00k | prime_basis_limb = other.prime_basis_limb; | 321 | 1.00k | return *this; | 322 | 1.00k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSERKS7_ Line | Count | Source | 314 | 5.54k | { | 315 | 5.54k | context = other.context; | 316 | 5.54k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 5.54k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 5.54k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 5.54k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 5.54k | prime_basis_limb = other.prime_basis_limb; | 321 | 5.54k | return *this; | 322 | 5.54k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSERKS7_ Line | Count | Source | 314 | 15 | { | 315 | 15 | context = other.context; | 316 | 15 | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 317 | 15 | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 318 | 15 | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 319 | 15 | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 320 | 15 | prime_basis_limb = other.prime_basis_limb; | 321 | 15 | return *this; | 322 | 15 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSERKS9_ |
323 | | |
324 | | template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(bigfield&& other) |
325 | 4.23M | { |
326 | 4.23M | context = other.context; |
327 | 4.23M | binary_basis_limbs[0] = other.binary_basis_limbs[0]; |
328 | 4.23M | binary_basis_limbs[1] = other.binary_basis_limbs[1]; |
329 | 4.23M | binary_basis_limbs[2] = other.binary_basis_limbs[2]; |
330 | 4.23M | binary_basis_limbs[3] = other.binary_basis_limbs[3]; |
331 | 4.23M | prime_basis_limb = other.prime_basis_limb; |
332 | 4.23M | return *this; |
333 | 4.23M | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSEOS6_ Line | Count | Source | 325 | 3.97M | { | 326 | 3.97M | context = other.context; | 327 | 3.97M | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 3.97M | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 3.97M | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 3.97M | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 3.97M | prime_basis_limb = other.prime_basis_limb; | 332 | 3.97M | return *this; | 333 | 3.97M | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSEOS6_ Line | Count | Source | 325 | 1.13k | { | 326 | 1.13k | context = other.context; | 327 | 1.13k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 1.13k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 1.13k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 1.13k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 1.13k | prime_basis_limb = other.prime_basis_limb; | 332 | 1.13k | return *this; | 333 | 1.13k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSEOS8_ Line | Count | Source | 325 | 48 | { | 326 | 48 | context = other.context; | 327 | 48 | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 48 | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 48 | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 48 | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 48 | prime_basis_limb = other.prime_basis_limb; | 332 | 48 | return *this; | 333 | 48 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSEOS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSEOS7_ Line | Count | Source | 325 | 10.2k | { | 326 | 10.2k | context = other.context; | 327 | 10.2k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 10.2k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 10.2k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 10.2k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 10.2k | prime_basis_limb = other.prime_basis_limb; | 332 | 10.2k | return *this; | 333 | 10.2k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSEOS7_ Line | Count | Source | 325 | 126 | { | 326 | 126 | context = other.context; | 327 | 126 | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 126 | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 126 | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 126 | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 126 | prime_basis_limb = other.prime_basis_limb; | 332 | 126 | return *this; | 333 | 126 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSEOS9_ Line | Count | Source | 325 | 225k | { | 326 | 225k | context = other.context; | 327 | 225k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 225k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 225k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 225k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 225k | prime_basis_limb = other.prime_basis_limb; | 332 | 225k | return *this; | 333 | 225k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSEOS9_ Line | Count | Source | 325 | 2.59k | { | 326 | 2.59k | context = other.context; | 327 | 2.59k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 2.59k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 2.59k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 2.59k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 2.59k | prime_basis_limb = other.prime_basis_limb; | 332 | 2.59k | return *this; | 333 | 2.59k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSEOS7_ Line | Count | Source | 325 | 14.7k | { | 326 | 14.7k | context = other.context; | 327 | 14.7k | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 14.7k | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 14.7k | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 14.7k | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 14.7k | prime_basis_limb = other.prime_basis_limb; | 332 | 14.7k | return *this; | 333 | 14.7k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSEOS7_ Line | Count | Source | 325 | 70 | { | 326 | 70 | context = other.context; | 327 | 70 | binary_basis_limbs[0] = other.binary_basis_limbs[0]; | 328 | 70 | binary_basis_limbs[1] = other.binary_basis_limbs[1]; | 329 | 70 | binary_basis_limbs[2] = other.binary_basis_limbs[2]; | 330 | 70 | binary_basis_limbs[3] = other.binary_basis_limbs[3]; | 331 | 70 | prime_basis_limb = other.prime_basis_limb; | 332 | 70 | return *this; | 333 | 70 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSEOS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSEOS9_ |
334 | | |
335 | | template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_value() const |
336 | 8.12M | { |
337 | 8.12M | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); |
338 | 8.12M | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); |
339 | 8.12M | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); |
340 | 8.12M | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); |
341 | 8.12M | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); |
342 | 8.12M | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9get_valueEv Line | Count | Source | 336 | 7.45M | { | 337 | 7.45M | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 7.45M | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 7.45M | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 7.45M | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 7.45M | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 7.45M | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9get_valueEv Line | Count | Source | 336 | 847 | { | 337 | 847 | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 847 | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 847 | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 847 | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 847 | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 847 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9get_valueEv Line | Count | Source | 336 | 67 | { | 337 | 67 | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 67 | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 67 | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 67 | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 67 | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 67 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9get_valueEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9get_valueEv Line | Count | Source | 336 | 27.1k | { | 337 | 27.1k | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 27.1k | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 27.1k | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 27.1k | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 27.1k | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 27.1k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9get_valueEv Line | Count | Source | 336 | 218 | { | 337 | 218 | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 218 | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 218 | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 218 | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 218 | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 218 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9get_valueEv Line | Count | Source | 336 | 590k | { | 337 | 590k | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 590k | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 590k | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 590k | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 590k | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 590k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9get_valueEv Line | Count | Source | 336 | 4.60k | { | 337 | 4.60k | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 4.60k | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 4.60k | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 4.60k | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 4.60k | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 4.60k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9get_valueEv Line | Count | Source | 336 | 48.4k | { | 337 | 48.4k | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 48.4k | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 48.4k | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 48.4k | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 48.4k | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 48.4k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9get_valueEv Line | Count | Source | 336 | 100 | { | 337 | 100 | uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value()); | 338 | 100 | uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value()); | 339 | 100 | uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value()); | 340 | 100 | uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value()); | 341 | 100 | return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS)); | 342 | 100 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9get_valueEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9get_valueEv |
343 | | |
344 | | template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_maximum_value() const |
345 | 16.7M | { |
346 | 16.7M | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); |
347 | 16.7M | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; |
348 | 16.7M | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); |
349 | 16.7M | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); |
350 | 16.7M | return t0 + t1 + t2 + t3; |
351 | 16.7M | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 15.3M | { | 346 | 15.3M | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 15.3M | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 15.3M | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 15.3M | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 15.3M | return t0 + t1 + t2 + t3; | 351 | 15.3M | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 1.49k | { | 346 | 1.49k | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 1.49k | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 1.49k | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 1.49k | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 1.49k | return t0 + t1 + t2 + t3; | 351 | 1.49k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 64 | { | 346 | 64 | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 64 | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 64 | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 64 | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 64 | return t0 + t1 + t2 + t3; | 351 | 64 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17get_maximum_valueEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 55.1k | { | 346 | 55.1k | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 55.1k | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 55.1k | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 55.1k | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 55.1k | return t0 + t1 + t2 + t3; | 351 | 55.1k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 370 | { | 346 | 370 | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 370 | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 370 | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 370 | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 370 | return t0 + t1 + t2 + t3; | 351 | 370 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 1.22M | { | 346 | 1.22M | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 1.22M | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 1.22M | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 1.22M | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 1.22M | return t0 + t1 + t2 + t3; | 351 | 1.22M | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 7.48k | { | 346 | 7.48k | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 7.48k | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 7.48k | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 7.48k | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 7.48k | return t0 + t1 + t2 + t3; | 351 | 7.48k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 94.9k | { | 346 | 94.9k | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 94.9k | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 94.9k | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 94.9k | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 94.9k | return t0 + t1 + t2 + t3; | 351 | 94.9k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17get_maximum_valueEv Line | Count | Source | 345 | 156 | { | 346 | 156 | uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value); | 347 | 156 | uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS; | 348 | 156 | uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2); | 349 | 156 | uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3); | 350 | 156 | return t0 + t1 + t2 + t3; | 351 | 156 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17get_maximum_valueEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17get_maximum_valueEv |
352 | | |
353 | | /** |
354 | | * @brief Add a field element to the lower limb. CAUTION (the element has to be constrained before using this |
355 | | * function) |
356 | | * |
357 | | * @details Sometimes we need to add a small constrained value to a bigfield element (for example, a boolean value), |
358 | | * but we don't want to construct a full bigfield element for that as it would take too many gates. If the maximum |
359 | | * value of the field element being added is small enough, we can simply add it to the lowest limb and increase its |
360 | | * maximum value. That will create 2 additional constraints instead of 5/3 needed to add 2 bigfield elements and |
361 | | * several needed to construct a bigfield element. |
362 | | * |
363 | | * @tparam Builder Builder |
364 | | * @tparam T Field Parameters |
365 | | * @param other Field element that will be added to the lower |
366 | | * @param other_maximum_value The maximum value of other |
367 | | * @return bigfield<Builder, T> Result |
368 | | */ |
369 | | template <typename Builder, typename T> |
370 | | bigfield<Builder, T> bigfield<Builder, T>::add_to_lower_limb(const field_t<Builder>& other, |
371 | | uint256_t other_maximum_value) const |
372 | 1.20k | { |
373 | 1.20k | reduction_check(); |
374 | 1.20k | ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <= |
375 | 1.20k | uint512_t(get_maximum_unreduced_limb_value())); |
376 | | // needed cause a constant doesn't have a valid context |
377 | 1.20k | Builder* ctx = context ? context : other.context; |
378 | |
|
379 | 1.20k | if (is_constant() && other.is_constant()) { |
380 | 0 | return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512)); |
381 | 0 | } |
382 | | |
383 | 1.20k | bigfield result; |
384 | | // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness |
385 | 1.20k | if (is_constant()) { |
386 | 607 | auto context = other.context; |
387 | 2.42k | for (size_t i = 1; i < 4; i++) { |
388 | | // Construct a witness element from the original constant limb |
389 | 1.82k | result.binary_basis_limbs[i] = |
390 | 1.82k | Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()), |
391 | 1.82k | binary_basis_limbs[i].maximum_value); |
392 | | // Ensure it is fixed |
393 | 1.82k | result.binary_basis_limbs[i].element.fix_witness(); |
394 | 1.82k | result.context = ctx; |
395 | 1.82k | } |
396 | 607 | } else { |
397 | | |
398 | | // if this element is a witness, then all limbs will be witnesses |
399 | 600 | result = *this; |
400 | 600 | } |
401 | 1.20k | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value; |
402 | | |
403 | 1.20k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other; |
404 | 1.20k | result.prime_basis_limb = prime_basis_limb + other; |
405 | 1.20k | result.set_origin_tag(OriginTag(get_origin_tag(), other.tag)); |
406 | 1.20k | return result; |
407 | 0 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Line | Count | Source | 372 | 7 | { | 373 | 7 | reduction_check(); | 374 | 7 | ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <= | 375 | 7 | uint512_t(get_maximum_unreduced_limb_value())); | 376 | | // needed cause a constant doesn't have a valid context | 377 | 7 | Builder* ctx = context ? context : other.context; | 378 | | | 379 | 7 | if (is_constant() && other.is_constant()) { | 380 | 0 | return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512)); | 381 | 0 | } | 382 | | | 383 | 7 | bigfield result; | 384 | | // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness | 385 | 7 | if (is_constant()) { | 386 | 7 | auto context = other.context; | 387 | 28 | for (size_t i = 1; i < 4; i++) { | 388 | | // Construct a witness element from the original constant limb | 389 | 21 | result.binary_basis_limbs[i] = | 390 | 21 | Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()), | 391 | 21 | binary_basis_limbs[i].maximum_value); | 392 | | // Ensure it is fixed | 393 | 21 | result.binary_basis_limbs[i].element.fix_witness(); | 394 | 21 | result.context = ctx; | 395 | 21 | } | 396 | 7 | } else { | 397 | | | 398 | | // if this element is a witness, then all limbs will be witnesses | 399 | 0 | result = *this; | 400 | 0 | } | 401 | 7 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value; | 402 | | | 403 | 7 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other; | 404 | 7 | result.prime_basis_limb = prime_basis_limb + other; | 405 | 7 | result.set_origin_tag(OriginTag(get_origin_tag(), other.tag)); | 406 | 7 | return result; | 407 | 7 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Line | Count | Source | 372 | 48 | { | 373 | 48 | reduction_check(); | 374 | 48 | ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <= | 375 | 48 | uint512_t(get_maximum_unreduced_limb_value())); | 376 | | // needed cause a constant doesn't have a valid context | 377 | 48 | Builder* ctx = context ? context : other.context; | 378 | | | 379 | 48 | if (is_constant() && other.is_constant()) { | 380 | 0 | return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512)); | 381 | 0 | } | 382 | | | 383 | 48 | bigfield result; | 384 | | // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness | 385 | 48 | if (is_constant()) { | 386 | 24 | auto context = other.context; | 387 | 96 | for (size_t i = 1; i < 4; i++) { | 388 | | // Construct a witness element from the original constant limb | 389 | 72 | result.binary_basis_limbs[i] = | 390 | 72 | Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()), | 391 | 72 | binary_basis_limbs[i].maximum_value); | 392 | | // Ensure it is fixed | 393 | 72 | result.binary_basis_limbs[i].element.fix_witness(); | 394 | 72 | result.context = ctx; | 395 | 72 | } | 396 | 24 | } else { | 397 | | | 398 | | // if this element is a witness, then all limbs will be witnesses | 399 | 24 | result = *this; | 400 | 24 | } | 401 | 48 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value; | 402 | | | 403 | 48 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other; | 404 | 48 | result.prime_basis_limb = prime_basis_limb + other; | 405 | 48 | result.set_origin_tag(OriginTag(get_origin_tag(), other.tag)); | 406 | 48 | return result; | 407 | 48 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Line | Count | Source | 372 | 1.15k | { | 373 | 1.15k | reduction_check(); | 374 | 1.15k | ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <= | 375 | 1.15k | uint512_t(get_maximum_unreduced_limb_value())); | 376 | | // needed cause a constant doesn't have a valid context | 377 | 1.15k | Builder* ctx = context ? context : other.context; | 378 | | | 379 | 1.15k | if (is_constant() && other.is_constant()) { | 380 | 0 | return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512)); | 381 | 0 | } | 382 | | | 383 | 1.15k | bigfield result; | 384 | | // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness | 385 | 1.15k | if (is_constant()) { | 386 | 576 | auto context = other.context; | 387 | 2.30k | for (size_t i = 1; i < 4; i++) { | 388 | | // Construct a witness element from the original constant limb | 389 | 1.72k | result.binary_basis_limbs[i] = | 390 | 1.72k | Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()), | 391 | 1.72k | binary_basis_limbs[i].maximum_value); | 392 | | // Ensure it is fixed | 393 | 1.72k | result.binary_basis_limbs[i].element.fix_witness(); | 394 | 1.72k | result.context = ctx; | 395 | 1.72k | } | 396 | 576 | } else { | 397 | | | 398 | | // if this element is a witness, then all limbs will be witnesses | 399 | 576 | result = *this; | 400 | 576 | } | 401 | 1.15k | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value; | 402 | | | 403 | 1.15k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other; | 404 | 1.15k | result.prime_basis_limb = prime_basis_limb + other; | 405 | 1.15k | result.set_origin_tag(OriginTag(get_origin_tag(), other.tag)); | 406 | 1.15k | return result; | 407 | 1.15k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE |
408 | | |
409 | | template <typename Builder, typename T> |
410 | | bigfield<Builder, T> bigfield<Builder, T>::operator+(const bigfield& other) const |
411 | 182k | { |
412 | 182k | reduction_check(); |
413 | 182k | other.reduction_check(); |
414 | | // needed cause a constant doesn't have a valid context |
415 | 182k | Builder* ctx = context ? context : other.context; |
416 | | |
417 | 182k | if (is_constant() && other.is_constant()) { |
418 | 1.59k | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); |
419 | 1.59k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
420 | 1.59k | return result; |
421 | 1.59k | } |
422 | 180k | bigfield result(ctx); |
423 | 180k | result.binary_basis_limbs[0].maximum_value = |
424 | 180k | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; |
425 | 180k | result.binary_basis_limbs[1].maximum_value = |
426 | 180k | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; |
427 | 180k | result.binary_basis_limbs[2].maximum_value = |
428 | 180k | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; |
429 | 180k | result.binary_basis_limbs[3].maximum_value = |
430 | 180k | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; |
431 | | |
432 | 180k | if constexpr (HasPlookup<Builder>) { |
433 | 180k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && |
434 | 180k | !is_constant() && !other.is_constant()) { |
435 | 143k | bool limbconst = binary_basis_limbs[0].element.is_constant(); |
436 | 143k | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); |
437 | 143k | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); |
438 | 143k | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); |
439 | 143k | limbconst = limbconst || prime_basis_limb.is_constant(); |
440 | 143k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); |
441 | 143k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); |
442 | 143k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); |
443 | 143k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); |
444 | 143k | limbconst = limbconst || other.prime_basis_limb.is_constant(); |
445 | 143k | limbconst = |
446 | 143k | limbconst || (prime_basis_limb.get_witness_index() == |
447 | 143k | other.prime_basis_limb |
448 | 143k | .get_witness_index()); // We are comparing if the bigfield elements are exactly the |
449 | | // same object, so we compare the unnormalized witness indices |
450 | 143k | if (!limbconst) { |
451 | 29.4k | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, |
452 | 29.4k | binary_basis_limbs[0].element.multiplicative_constant }; |
453 | 29.4k | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, |
454 | 29.4k | binary_basis_limbs[1].element.multiplicative_constant }; |
455 | 29.4k | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, |
456 | 29.4k | binary_basis_limbs[2].element.multiplicative_constant }; |
457 | 29.4k | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, |
458 | 29.4k | binary_basis_limbs[3].element.multiplicative_constant }; |
459 | 29.4k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, |
460 | 29.4k | other.binary_basis_limbs[0].element.multiplicative_constant }; |
461 | 29.4k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, |
462 | 29.4k | other.binary_basis_limbs[1].element.multiplicative_constant }; |
463 | 29.4k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, |
464 | 29.4k | other.binary_basis_limbs[2].element.multiplicative_constant }; |
465 | 29.4k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, |
466 | 29.4k | other.binary_basis_limbs[3].element.multiplicative_constant }; |
467 | 29.4k | bb::fr c0(binary_basis_limbs[0].element.additive_constant + |
468 | 29.4k | other.binary_basis_limbs[0].element.additive_constant); |
469 | 29.4k | bb::fr c1(binary_basis_limbs[1].element.additive_constant + |
470 | 29.4k | other.binary_basis_limbs[1].element.additive_constant); |
471 | 29.4k | bb::fr c2(binary_basis_limbs[2].element.additive_constant + |
472 | 29.4k | other.binary_basis_limbs[2].element.additive_constant); |
473 | 29.4k | bb::fr c3(binary_basis_limbs[3].element.additive_constant + |
474 | 29.4k | other.binary_basis_limbs[3].element.additive_constant); |
475 | | |
476 | 29.4k | uint32_t xp(prime_basis_limb.witness_index); |
477 | 29.4k | uint32_t yp(other.prime_basis_limb.witness_index); |
478 | 29.4k | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); |
479 | 29.4k | const auto output_witnesses = ctx->evaluate_non_native_field_addition( |
480 | 29.4k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); |
481 | 29.4k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); |
482 | 29.4k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); |
483 | 29.4k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); |
484 | 29.4k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); |
485 | 29.4k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); |
486 | 29.4k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
487 | 29.4k | return result; |
488 | 29.4k | } |
489 | 143k | } |
490 | 180k | } |
491 | | |
492 | 151k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; |
493 | 151k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; |
494 | 151k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; |
495 | 151k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; |
496 | 151k | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; |
497 | 151k | return result; |
498 | 180k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEplERKS6_ Line | Count | Source | 411 | 145k | { | 412 | 145k | reduction_check(); | 413 | 145k | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 145k | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 145k | if (is_constant() && other.is_constant()) { | 418 | 1.59k | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 1.59k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 1.59k | return result; | 421 | 1.59k | } | 422 | 144k | bigfield result(ctx); | 423 | 144k | result.binary_basis_limbs[0].maximum_value = | 424 | 144k | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 144k | result.binary_basis_limbs[1].maximum_value = | 426 | 144k | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 144k | result.binary_basis_limbs[2].maximum_value = | 428 | 144k | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 144k | result.binary_basis_limbs[3].maximum_value = | 430 | 144k | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 144k | if constexpr (HasPlookup<Builder>) { | 433 | 144k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 144k | !is_constant() && !other.is_constant()) { | 435 | 113k | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 113k | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 113k | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 113k | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 113k | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 113k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 113k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 113k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 113k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 113k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 113k | limbconst = | 446 | 113k | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 113k | other.prime_basis_limb | 448 | 113k | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 113k | if (!limbconst) { | 451 | 29.4k | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 29.4k | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 29.4k | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 29.4k | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 29.4k | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 29.4k | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 29.4k | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 29.4k | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 29.4k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 29.4k | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 29.4k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 29.4k | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 29.4k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 29.4k | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 29.4k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 29.4k | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 29.4k | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 29.4k | other.binary_basis_limbs[0].element.additive_constant); | 469 | 29.4k | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 29.4k | other.binary_basis_limbs[1].element.additive_constant); | 471 | 29.4k | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 29.4k | other.binary_basis_limbs[2].element.additive_constant); | 473 | 29.4k | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 29.4k | other.binary_basis_limbs[3].element.additive_constant); | 475 | | | 476 | 29.4k | uint32_t xp(prime_basis_limb.witness_index); | 477 | 29.4k | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 29.4k | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 29.4k | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 29.4k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 29.4k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 29.4k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 29.4k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 29.4k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 29.4k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 29.4k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 29.4k | return result; | 488 | 29.4k | } | 489 | 113k | } | 490 | 144k | } | 491 | | | 492 | 114k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 114k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 114k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 114k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 114k | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 114k | return result; | 498 | 144k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEplERKS6_ Line | Count | Source | 411 | 39 | { | 412 | 39 | reduction_check(); | 413 | 39 | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 39 | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 39 | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 39 | bigfield result(ctx); | 423 | 39 | result.binary_basis_limbs[0].maximum_value = | 424 | 39 | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 39 | result.binary_basis_limbs[1].maximum_value = | 426 | 39 | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 39 | result.binary_basis_limbs[2].maximum_value = | 428 | 39 | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 39 | result.binary_basis_limbs[3].maximum_value = | 430 | 39 | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 39 | if constexpr (HasPlookup<Builder>) { | 433 | 39 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 39 | !is_constant() && !other.is_constant()) { | 435 | 30 | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 30 | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 30 | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 30 | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 30 | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 30 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 30 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 30 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 30 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 30 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 30 | limbconst = | 446 | 30 | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 30 | other.prime_basis_limb | 448 | 30 | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 30 | if (!limbconst) { | 451 | 27 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 27 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 27 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 27 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 27 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 27 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 27 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 27 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 27 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 27 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 27 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 27 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 27 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 27 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 27 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 27 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 27 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 27 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 27 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 27 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 27 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 27 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 27 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 27 | other.binary_basis_limbs[3].element.additive_constant); | 475 | | | 476 | 27 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 27 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 27 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 27 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 27 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 27 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 27 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 27 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 27 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 27 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 27 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 27 | return result; | 488 | 27 | } | 489 | 30 | } | 490 | 39 | } | 491 | | | 492 | 12 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 12 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 12 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 12 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 12 | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 12 | return result; | 498 | 39 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEplERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EplERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEplERKS7_ Line | Count | Source | 411 | 1.73k | { | 412 | 1.73k | reduction_check(); | 413 | 1.73k | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 1.73k | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 1.73k | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 1.73k | bigfield result(ctx); | 423 | 1.73k | result.binary_basis_limbs[0].maximum_value = | 424 | 1.73k | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 1.73k | result.binary_basis_limbs[1].maximum_value = | 426 | 1.73k | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 1.73k | result.binary_basis_limbs[2].maximum_value = | 428 | 1.73k | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 1.73k | result.binary_basis_limbs[3].maximum_value = | 430 | 1.73k | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 1.73k | if constexpr (HasPlookup<Builder>) { | 433 | 1.73k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 1.73k | !is_constant() && !other.is_constant()) { | 435 | 1.36k | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 1.36k | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 1.36k | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 1.36k | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 1.36k | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 1.36k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 1.36k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 1.36k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 1.36k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 1.36k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 1.36k | limbconst = | 446 | 1.36k | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 1.36k | other.prime_basis_limb | 448 | 1.36k | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 1.36k | if (!limbconst) { | 451 | 18 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 18 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 18 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 18 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 18 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 18 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 18 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 18 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 18 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 18 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 18 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 18 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 18 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 18 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 18 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 18 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 18 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 18 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 18 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 18 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 18 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 18 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 18 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 18 | other.binary_basis_limbs[3].element.additive_constant); | 475 | | | 476 | 18 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 18 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 18 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 18 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 18 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 18 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 18 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 18 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 18 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 18 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 18 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 18 | return result; | 488 | 18 | } | 489 | 1.36k | } | 490 | 1.73k | } | 491 | | | 492 | 1.72k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 1.72k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 1.72k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 1.72k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 1.72k | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 1.72k | return result; | 498 | 1.73k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEplERKS7_ Line | Count | Source | 411 | 25 | { | 412 | 25 | reduction_check(); | 413 | 25 | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 25 | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 25 | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 25 | bigfield result(ctx); | 423 | 25 | result.binary_basis_limbs[0].maximum_value = | 424 | 25 | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 25 | result.binary_basis_limbs[1].maximum_value = | 426 | 25 | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 25 | result.binary_basis_limbs[2].maximum_value = | 428 | 25 | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 25 | result.binary_basis_limbs[3].maximum_value = | 430 | 25 | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 25 | if constexpr (HasPlookup<Builder>) { | 433 | 25 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 25 | !is_constant() && !other.is_constant()) { | 435 | 25 | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 25 | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 25 | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 25 | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 25 | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 25 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 25 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 25 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 25 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 25 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 25 | limbconst = | 446 | 25 | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 25 | other.prime_basis_limb | 448 | 25 | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 25 | if (!limbconst) { | 451 | 1 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 1 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 1 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 1 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 1 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 1 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 1 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 1 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 1 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 1 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 1 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 1 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 1 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 1 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 1 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 1 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 1 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 1 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 1 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 1 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 1 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 1 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 1 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 1 | other.binary_basis_limbs[3].element.additive_constant); | 475 | | | 476 | 1 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 1 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 1 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 1 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 1 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 1 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 1 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 1 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 1 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 1 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 1 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 1 | return result; | 488 | 1 | } | 489 | 25 | } | 490 | 25 | } | 491 | | | 492 | 24 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 24 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 24 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 24 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 24 | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 24 | return result; | 498 | 25 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEplERKS9_ Line | Count | Source | 411 | 32.8k | { | 412 | 32.8k | reduction_check(); | 413 | 32.8k | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 32.8k | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 32.8k | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 32.8k | bigfield result(ctx); | 423 | 32.8k | result.binary_basis_limbs[0].maximum_value = | 424 | 32.8k | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 32.8k | result.binary_basis_limbs[1].maximum_value = | 426 | 32.8k | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 32.8k | result.binary_basis_limbs[2].maximum_value = | 428 | 32.8k | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 32.8k | result.binary_basis_limbs[3].maximum_value = | 430 | 32.8k | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 32.8k | if constexpr (HasPlookup<Builder>) { | 433 | 32.8k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 32.8k | !is_constant() && !other.is_constant()) { | 435 | 26.4k | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 26.4k | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 26.4k | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 26.4k | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 26.4k | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 26.4k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 26.4k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 26.4k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 26.4k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 26.4k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 26.4k | limbconst = | 446 | 26.4k | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 26.4k | other.prime_basis_limb | 448 | 26.4k | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 26.4k | if (!limbconst) { | 451 | 0 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 0 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 0 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 0 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 0 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 0 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 0 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 0 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 0 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 0 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 0 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 0 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 0 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 0 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 0 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 0 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 0 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 0 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 0 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 0 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 0 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 0 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 0 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 0 | other.binary_basis_limbs[3].element.additive_constant); | 475 | |
| 476 | 0 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 0 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 0 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 0 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 0 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 0 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 0 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 0 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 0 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 0 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 0 | return result; | 488 | 0 | } | 489 | 26.4k | } | 490 | 32.8k | } | 491 | | | 492 | 32.8k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 32.8k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 32.8k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 32.8k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 32.8k | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 32.8k | return result; | 498 | 32.8k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEplERKS9_ Line | Count | Source | 411 | 576 | { | 412 | 576 | reduction_check(); | 413 | 576 | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 576 | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 576 | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 576 | bigfield result(ctx); | 423 | 576 | result.binary_basis_limbs[0].maximum_value = | 424 | 576 | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 576 | result.binary_basis_limbs[1].maximum_value = | 426 | 576 | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 576 | result.binary_basis_limbs[2].maximum_value = | 428 | 576 | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 576 | result.binary_basis_limbs[3].maximum_value = | 430 | 576 | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 576 | if constexpr (HasPlookup<Builder>) { | 433 | 576 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 576 | !is_constant() && !other.is_constant()) { | 435 | 576 | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 576 | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 576 | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 576 | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 576 | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 576 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 576 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 576 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 576 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 576 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 576 | limbconst = | 446 | 576 | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 576 | other.prime_basis_limb | 448 | 576 | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 576 | if (!limbconst) { | 451 | 0 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 0 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 0 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 0 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 0 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 0 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 0 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 0 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 0 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 0 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 0 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 0 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 0 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 0 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 0 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 0 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 0 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 0 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 0 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 0 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 0 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 0 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 0 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 0 | other.binary_basis_limbs[3].element.additive_constant); | 475 | |
| 476 | 0 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 0 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 0 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 0 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 0 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 0 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 0 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 0 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 0 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 0 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 0 | return result; | 488 | 0 | } | 489 | 576 | } | 490 | 576 | } | 491 | | | 492 | 576 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 576 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 576 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 576 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 576 | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 576 | return result; | 498 | 576 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEplERKS7_ Line | Count | Source | 411 | 1.34k | { | 412 | 1.34k | reduction_check(); | 413 | 1.34k | other.reduction_check(); | 414 | | // needed cause a constant doesn't have a valid context | 415 | 1.34k | Builder* ctx = context ? context : other.context; | 416 | | | 417 | 1.34k | if (is_constant() && other.is_constant()) { | 418 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512)); | 419 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 420 | 0 | return result; | 421 | 0 | } | 422 | 1.34k | bigfield result(ctx); | 423 | 1.34k | result.binary_basis_limbs[0].maximum_value = | 424 | 1.34k | binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value; | 425 | 1.34k | result.binary_basis_limbs[1].maximum_value = | 426 | 1.34k | binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value; | 427 | 1.34k | result.binary_basis_limbs[2].maximum_value = | 428 | 1.34k | binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value; | 429 | 1.34k | result.binary_basis_limbs[3].maximum_value = | 430 | 1.34k | binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value; | 431 | | | 432 | 1.34k | if constexpr (HasPlookup<Builder>) { | 433 | 1.34k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 434 | 1.34k | !is_constant() && !other.is_constant()) { | 435 | 1.30k | bool limbconst = binary_basis_limbs[0].element.is_constant(); | 436 | 1.30k | limbconst = limbconst || binary_basis_limbs[1].element.is_constant(); | 437 | 1.30k | limbconst = limbconst || binary_basis_limbs[2].element.is_constant(); | 438 | 1.30k | limbconst = limbconst || binary_basis_limbs[3].element.is_constant(); | 439 | 1.30k | limbconst = limbconst || prime_basis_limb.is_constant(); | 440 | 1.30k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 441 | 1.30k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 442 | 1.30k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 443 | 1.30k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 444 | 1.30k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 445 | 1.30k | limbconst = | 446 | 1.30k | limbconst || (prime_basis_limb.get_witness_index() == | 447 | 1.30k | other.prime_basis_limb | 448 | 1.30k | .get_witness_index()); // We are comparing if the bigfield elements are exactly the | 449 | | // same object, so we compare the unnormalized witness indices | 450 | 1.30k | if (!limbconst) { | 451 | 0 | std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index, | 452 | 0 | binary_basis_limbs[0].element.multiplicative_constant }; | 453 | 0 | std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index, | 454 | 0 | binary_basis_limbs[1].element.multiplicative_constant }; | 455 | 0 | std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index, | 456 | 0 | binary_basis_limbs[2].element.multiplicative_constant }; | 457 | 0 | std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index, | 458 | 0 | binary_basis_limbs[3].element.multiplicative_constant }; | 459 | 0 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 460 | 0 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 461 | 0 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 462 | 0 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 463 | 0 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 464 | 0 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 465 | 0 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 466 | 0 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 467 | 0 | bb::fr c0(binary_basis_limbs[0].element.additive_constant + | 468 | 0 | other.binary_basis_limbs[0].element.additive_constant); | 469 | 0 | bb::fr c1(binary_basis_limbs[1].element.additive_constant + | 470 | 0 | other.binary_basis_limbs[1].element.additive_constant); | 471 | 0 | bb::fr c2(binary_basis_limbs[2].element.additive_constant + | 472 | 0 | other.binary_basis_limbs[2].element.additive_constant); | 473 | 0 | bb::fr c3(binary_basis_limbs[3].element.additive_constant + | 474 | 0 | other.binary_basis_limbs[3].element.additive_constant); | 475 | |
| 476 | 0 | uint32_t xp(prime_basis_limb.witness_index); | 477 | 0 | uint32_t yp(other.prime_basis_limb.witness_index); | 478 | 0 | bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant); | 479 | 0 | const auto output_witnesses = ctx->evaluate_non_native_field_addition( | 480 | 0 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 481 | 0 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 482 | 0 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 483 | 0 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 484 | 0 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 485 | 0 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 486 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 487 | 0 | return result; | 488 | 0 | } | 489 | 1.30k | } | 490 | 1.34k | } | 491 | | | 492 | 1.34k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element; | 493 | 1.34k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element; | 494 | 1.34k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element; | 495 | 1.34k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element; | 496 | 1.34k | result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb; | 497 | 1.34k | return result; | 498 | 1.34k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEplERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEplERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEplERKS9_ |
499 | | |
500 | | /** |
501 | | * @brief Create constraints for summing three |
502 | | * bigfield elements efficiently |
503 | | * |
504 | | * @tparam Builder |
505 | | * @tparam T |
506 | | * @param add_a |
507 | | * @param add_b |
508 | | * @return The sum of three terms |
509 | | */ |
510 | | template <typename Builder, typename T> |
511 | | bigfield<Builder, T> bigfield<Builder, T>::add_two(const bigfield& add_a, const bigfield& add_b) const |
512 | 0 | { |
513 | 0 | reduction_check(); |
514 | 0 | add_a.reduction_check(); |
515 | 0 | add_b.reduction_check(); |
516 | |
|
517 | 0 | Builder* ctx = (context == nullptr) ? (add_a.context == nullptr ? add_b.context : add_a.context) : context; |
518 | |
|
519 | 0 | if (is_constant() && add_a.is_constant() && add_b.is_constant()) { |
520 | 0 | auto result = bigfield(ctx, uint256_t((get_value() + add_a.get_value() + add_b.get_value()) % modulus_u512)); |
521 | 0 | result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag())); |
522 | 0 | return result; |
523 | 0 | } |
524 | | |
525 | 0 | bigfield result(ctx); |
526 | 0 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + |
527 | 0 | add_a.binary_basis_limbs[0].maximum_value + |
528 | 0 | add_b.binary_basis_limbs[0].maximum_value; |
529 | 0 | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + |
530 | 0 | add_a.binary_basis_limbs[1].maximum_value + |
531 | 0 | add_b.binary_basis_limbs[1].maximum_value; |
532 | 0 | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + |
533 | 0 | add_a.binary_basis_limbs[2].maximum_value + |
534 | 0 | add_b.binary_basis_limbs[2].maximum_value; |
535 | 0 | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + |
536 | 0 | add_a.binary_basis_limbs[3].maximum_value + |
537 | 0 | add_b.binary_basis_limbs[3].maximum_value; |
538 | |
|
539 | 0 | result.binary_basis_limbs[0].element = |
540 | 0 | binary_basis_limbs[0].element.add_two(add_a.binary_basis_limbs[0].element, add_b.binary_basis_limbs[0].element); |
541 | 0 | result.binary_basis_limbs[1].element = |
542 | 0 | binary_basis_limbs[1].element.add_two(add_a.binary_basis_limbs[1].element, add_b.binary_basis_limbs[1].element); |
543 | 0 | result.binary_basis_limbs[2].element = |
544 | 0 | binary_basis_limbs[2].element.add_two(add_a.binary_basis_limbs[2].element, add_b.binary_basis_limbs[2].element); |
545 | 0 | result.binary_basis_limbs[3].element = |
546 | 0 | binary_basis_limbs[3].element.add_two(add_a.binary_basis_limbs[3].element, add_b.binary_basis_limbs[3].element); |
547 | 0 | result.prime_basis_limb = prime_basis_limb.add_two(add_a.prime_basis_limb, add_b.prime_basis_limb); |
548 | 0 | result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag())); |
549 | 0 | return result; |
550 | 0 | } Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE7add_twoERKS6_S8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE7add_twoERKS6_S8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE7add_twoERKS8_SA_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E7add_twoERKS7_S9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE7add_twoERKS7_S9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE7add_twoERKS7_S9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE7add_twoERKS9_SB_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE7add_twoERKS9_SB_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE7add_twoERKS7_S9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE7add_twoERKS7_S9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE7add_twoERKS9_SB_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE7add_twoERKS9_SB_ |
551 | | |
552 | | // to make sure we don't go to negative values, add p before subtracting other |
553 | | /** |
554 | | * Subtraction operator. |
555 | | * |
556 | | * Like operator+, we use lazy reduction techniques to save on field reductions. |
557 | | * |
558 | | * Instead of computing `*this - other`, we compute offset X and compute: |
559 | | * `*this + X - other` |
560 | | * This ensures we do not underflow! |
561 | | * |
562 | | * Offset `X` will be a multiple of our bigfield modulus `p` |
563 | | * |
564 | | * i.e `X = m * p` |
565 | | * |
566 | | * It is NOT enough to ensure that the integer value of `*this + X - other` does not underflow. |
567 | | * We must ALSO ensure that each LIMB of the result does not underflow |
568 | | * |
569 | | * We must compute the MINIMUM value of `m` that ensures that none of the bigfield limbs will underflow! |
570 | | * |
571 | | * i.e. We must compute the MINIMUM value of `m` such that, for each limb `i`, the following result is positive: |
572 | | * |
573 | | * *this.limb[i] + X.limb[i] - other.limb[i] |
574 | | **/ |
575 | | template <typename Builder, typename T> |
576 | | bigfield<Builder, T> bigfield<Builder, T>::operator-(const bigfield& other) const |
577 | 2.02M | { |
578 | 2.02M | Builder* ctx = context ? context : other.context; |
579 | 2.02M | reduction_check(); |
580 | 2.02M | other.reduction_check(); |
581 | | |
582 | 2.02M | if (is_constant() && other.is_constant()) { |
583 | 9.57k | uint512_t left = get_value() % modulus_u512; |
584 | 9.57k | uint512_t right = other.get_value() % modulus_u512; |
585 | 9.57k | uint512_t out = (left + modulus_u512 - right) % modulus_u512; |
586 | | |
587 | 9.57k | auto result = bigfield(ctx, uint256_t(out.lo)); |
588 | 9.57k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
589 | 9.57k | return result; |
590 | 9.57k | } |
591 | | |
592 | 2.02M | if (other.is_constant()) { |
593 | 12.2k | uint512_t right = other.get_value() % modulus_u512; |
594 | 12.2k | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; |
595 | 12.2k | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); |
596 | 12.2k | } |
597 | | |
598 | | /** |
599 | | * Plookup bigfield subtractoin |
600 | | * |
601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) |
602 | | * This is in addition to the regular addition gate |
603 | | * |
604 | | * We can arrange our wires in memory like this: |
605 | | * |
606 | | * | 1 | 2 | 3 | 4 | |
607 | | * |-----|-----|-----|-----| |
608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) |
609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) |
610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) |
611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) |
612 | | * |
613 | | **/ |
614 | | |
615 | 2.00M | bigfield result(ctx); |
616 | | |
617 | | /** |
618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb |
619 | | * |
620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from |
621 | | * the next significant limb to ensure each limb value is positive? |
622 | | * |
623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result |
624 | | **/ |
625 | 2.00M | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; |
626 | | |
627 | | // Compute maximum shift factor for limb_0 |
628 | 2.00M | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
629 | | |
630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow |
631 | 2.00M | uint256_t limb_1_maximum_value = |
632 | 2.00M | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); |
633 | | |
634 | | // repeat the above for the remaining limbs |
635 | 2.00M | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
636 | 2.00M | uint256_t limb_2_maximum_value = |
637 | 2.00M | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); |
638 | 2.00M | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
639 | | |
640 | 2.00M | uint256_t limb_3_maximum_value = |
641 | 2.00M | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); |
642 | | |
643 | | /** |
644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 |
645 | | * |
646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. |
647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive |
648 | | * |
649 | | * Start by setting constant_to_add = p |
650 | | **/ |
651 | 2.00M | uint512_t constant_to_add = modulus_u512; |
652 | | // add a large enough multiple of p to not get negative result in subtraction |
653 | 4.10M | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { |
654 | 2.09M | constant_to_add += modulus_u512; |
655 | 2.09M | } |
656 | | |
657 | | /** |
658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive |
659 | | * |
660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] |
661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], |
662 | | *constant_to_add.limb[0] |
663 | | * |
664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: |
665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) |
666 | | * |
667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, |
668 | | * the value we borrow from t1 is subtracted from t2 |
669 | | * the value we borrow from t2 is equal to t3 |
670 | | **/ |
671 | 2.00M | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); |
672 | 2.00M | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); |
673 | 2.00M | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); |
674 | 2.00M | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); |
675 | | |
676 | | /** |
677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result |
678 | | *limb is positive |
679 | | **/ |
680 | 2.00M | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; |
681 | 2.00M | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; |
682 | 2.00M | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; |
683 | 2.00M | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; |
684 | | |
685 | | /** |
686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 |
687 | | **/ |
688 | 2.00M | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; |
689 | 2.00M | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; |
690 | 2.00M | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; |
691 | 2.00M | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; |
692 | | |
693 | | /** |
694 | | * Compute the binary basis limbs of our result |
695 | | **/ |
696 | 2.00M | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); |
697 | 2.00M | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); |
698 | 2.00M | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); |
699 | 2.00M | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); |
700 | | |
701 | 2.00M | if constexpr (HasPlookup<Builder>) { |
702 | 2.00M | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && |
703 | 2.00M | !is_constant() && !other.is_constant()) { |
704 | 879k | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); |
705 | 879k | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); |
706 | 879k | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); |
707 | 879k | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); |
708 | 879k | limbconst = limbconst || prime_basis_limb.is_constant(); |
709 | 879k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); |
710 | 879k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); |
711 | 879k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); |
712 | 879k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); |
713 | 879k | limbconst = limbconst || other.prime_basis_limb.is_constant(); |
714 | 879k | limbconst = |
715 | 879k | limbconst || |
716 | 879k | (prime_basis_limb.witness_index == |
717 | 879k | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we |
718 | | // need to compare the actual indices, not normalized ones |
719 | 879k | if (!limbconst) { |
720 | 879k | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, |
721 | 879k | binary_basis_limbs[0].element.multiplicative_constant }; |
722 | 879k | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, |
723 | 879k | binary_basis_limbs[1].element.multiplicative_constant }; |
724 | 879k | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, |
725 | 879k | binary_basis_limbs[2].element.multiplicative_constant }; |
726 | 879k | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, |
727 | 879k | binary_basis_limbs[3].element.multiplicative_constant }; |
728 | 879k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, |
729 | 879k | other.binary_basis_limbs[0].element.multiplicative_constant }; |
730 | 879k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, |
731 | 879k | other.binary_basis_limbs[1].element.multiplicative_constant }; |
732 | 879k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, |
733 | 879k | other.binary_basis_limbs[2].element.multiplicative_constant }; |
734 | 879k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, |
735 | 879k | other.binary_basis_limbs[3].element.multiplicative_constant }; |
736 | 879k | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - |
737 | 879k | other.binary_basis_limbs[0].element.additive_constant); |
738 | 879k | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - |
739 | 879k | other.binary_basis_limbs[1].element.additive_constant); |
740 | 879k | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - |
741 | 879k | other.binary_basis_limbs[2].element.additive_constant); |
742 | 879k | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - |
743 | 879k | other.binary_basis_limbs[3].element.additive_constant); |
744 | | |
745 | 879k | uint32_t xp(prime_basis_limb.witness_index); |
746 | 879k | uint32_t yp(other.prime_basis_limb.witness_index); |
747 | 879k | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); |
748 | 879k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; |
749 | 879k | cp += bb::fr(constant_to_add_mod_p.lo); |
750 | | |
751 | 879k | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( |
752 | 879k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); |
753 | | |
754 | 879k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); |
755 | 879k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); |
756 | 879k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); |
757 | 879k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); |
758 | 879k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); |
759 | | |
760 | 879k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
761 | 879k | return result; |
762 | 879k | } |
763 | 879k | } |
764 | 2.00M | } |
765 | | |
766 | 1.12M | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; |
767 | 1.12M | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; |
768 | 1.12M | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; |
769 | 1.12M | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; |
770 | | |
771 | | /** |
772 | | * Compute the prime basis limb of the result |
773 | | **/ |
774 | 1.12M | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; |
775 | 1.12M | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); |
776 | 1.12M | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; |
777 | 1.12M | result.prime_basis_limb -= other.prime_basis_limb; |
778 | 1.12M | return result; |
779 | 2.00M | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmiERKS6_ Line | Count | Source | 577 | 1.84M | { | 578 | 1.84M | Builder* ctx = context ? context : other.context; | 579 | 1.84M | reduction_check(); | 580 | 1.84M | other.reduction_check(); | 581 | | | 582 | 1.84M | if (is_constant() && other.is_constant()) { | 583 | 9.07k | uint512_t left = get_value() % modulus_u512; | 584 | 9.07k | uint512_t right = other.get_value() % modulus_u512; | 585 | 9.07k | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | | | 587 | 9.07k | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 9.07k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 9.07k | return result; | 590 | 9.07k | } | 591 | | | 592 | 1.83M | if (other.is_constant()) { | 593 | 12.2k | uint512_t right = other.get_value() % modulus_u512; | 594 | 12.2k | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 12.2k | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 12.2k | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 1.82M | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 1.82M | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 1.82M | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 1.82M | uint256_t limb_1_maximum_value = | 632 | 1.82M | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 1.82M | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 1.82M | uint256_t limb_2_maximum_value = | 637 | 1.82M | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 1.82M | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 1.82M | uint256_t limb_3_maximum_value = | 641 | 1.82M | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 1.82M | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 3.72M | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 1.90M | constant_to_add += modulus_u512; | 655 | 1.90M | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 1.82M | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 1.82M | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 1.82M | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 1.82M | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 1.82M | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 1.82M | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 1.82M | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 1.82M | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 1.82M | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 1.82M | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 1.82M | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 1.82M | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 1.82M | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 1.82M | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 1.82M | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 1.82M | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 1.82M | if constexpr (HasPlookup<Builder>) { | 702 | 1.82M | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 1.82M | !is_constant() && !other.is_constant()) { | 704 | 807k | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 807k | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 807k | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 807k | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 807k | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 807k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 807k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 807k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 807k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 807k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 807k | limbconst = | 715 | 807k | limbconst || | 716 | 807k | (prime_basis_limb.witness_index == | 717 | 807k | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 807k | if (!limbconst) { | 720 | 807k | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 807k | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 807k | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 807k | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 807k | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 807k | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 807k | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 807k | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 807k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 807k | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 807k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 807k | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 807k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 807k | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 807k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 807k | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 807k | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 807k | other.binary_basis_limbs[0].element.additive_constant); | 738 | 807k | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 807k | other.binary_basis_limbs[1].element.additive_constant); | 740 | 807k | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 807k | other.binary_basis_limbs[2].element.additive_constant); | 742 | 807k | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 807k | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 807k | uint32_t xp(prime_basis_limb.witness_index); | 746 | 807k | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 807k | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 807k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 807k | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 807k | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 807k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 807k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 807k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 807k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 807k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 807k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 807k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 807k | return result; | 762 | 807k | } | 763 | 807k | } | 764 | 1.82M | } | 765 | | | 766 | 1.01M | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 1.01M | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 1.01M | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 1.01M | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 1.01M | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 1.01M | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 1.01M | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 1.01M | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 1.01M | return result; | 779 | 1.82M | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmiERKS6_ Line | Count | Source | 577 | 653 | { | 578 | 653 | Builder* ctx = context ? context : other.context; | 579 | 653 | reduction_check(); | 580 | 653 | other.reduction_check(); | 581 | | | 582 | 653 | if (is_constant() && other.is_constant()) { | 583 | 0 | uint512_t left = get_value() % modulus_u512; | 584 | 0 | uint512_t right = other.get_value() % modulus_u512; | 585 | 0 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | |
| 587 | 0 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 0 | return result; | 590 | 0 | } | 591 | | | 592 | 653 | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 653 | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 653 | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 653 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 653 | uint256_t limb_1_maximum_value = | 632 | 653 | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 653 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 653 | uint256_t limb_2_maximum_value = | 637 | 653 | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 653 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 653 | uint256_t limb_3_maximum_value = | 641 | 653 | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 653 | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 1.34k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 690 | constant_to_add += modulus_u512; | 655 | 690 | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 653 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 653 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 653 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 653 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 653 | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 653 | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 653 | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 653 | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 653 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 653 | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 653 | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 653 | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 653 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 653 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 653 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 653 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 653 | if constexpr (HasPlookup<Builder>) { | 702 | 653 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 653 | !is_constant() && !other.is_constant()) { | 704 | 641 | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 641 | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 641 | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 641 | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 641 | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 641 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 641 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 641 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 641 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 641 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 641 | limbconst = | 715 | 641 | limbconst || | 716 | 641 | (prime_basis_limb.witness_index == | 717 | 641 | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 641 | if (!limbconst) { | 720 | 641 | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 641 | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 641 | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 641 | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 641 | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 641 | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 641 | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 641 | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 641 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 641 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 641 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 641 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 641 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 641 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 641 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 641 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 641 | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 641 | other.binary_basis_limbs[0].element.additive_constant); | 738 | 641 | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 641 | other.binary_basis_limbs[1].element.additive_constant); | 740 | 641 | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 641 | other.binary_basis_limbs[2].element.additive_constant); | 742 | 641 | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 641 | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 641 | uint32_t xp(prime_basis_limb.witness_index); | 746 | 641 | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 641 | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 641 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 641 | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 641 | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 641 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 641 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 641 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 641 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 641 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 641 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 641 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 641 | return result; | 762 | 641 | } | 763 | 641 | } | 764 | 653 | } | 765 | | | 766 | 12 | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 12 | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 12 | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 12 | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 12 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 12 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 12 | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 12 | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 12 | return result; | 779 | 653 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmiERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmiERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmiERKS7_ Line | Count | Source | 577 | 7.23k | { | 578 | 7.23k | Builder* ctx = context ? context : other.context; | 579 | 7.23k | reduction_check(); | 580 | 7.23k | other.reduction_check(); | 581 | | | 582 | 7.23k | if (is_constant() && other.is_constant()) { | 583 | 18 | uint512_t left = get_value() % modulus_u512; | 584 | 18 | uint512_t right = other.get_value() % modulus_u512; | 585 | 18 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | | | 587 | 18 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 18 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 18 | return result; | 590 | 18 | } | 591 | | | 592 | 7.21k | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 7.21k | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 7.21k | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 7.21k | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 7.21k | uint256_t limb_1_maximum_value = | 632 | 7.21k | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 7.21k | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 7.21k | uint256_t limb_2_maximum_value = | 637 | 7.21k | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 7.21k | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 7.21k | uint256_t limb_3_maximum_value = | 641 | 7.21k | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 7.21k | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 14.9k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 7.75k | constant_to_add += modulus_u512; | 655 | 7.75k | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 7.21k | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 7.21k | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 7.21k | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 7.21k | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 7.21k | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 7.21k | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 7.21k | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 7.21k | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 7.21k | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 7.21k | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 7.21k | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 7.21k | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 7.21k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 7.21k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 7.21k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 7.21k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 7.21k | if constexpr (HasPlookup<Builder>) { | 702 | 7.21k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 7.21k | !is_constant() && !other.is_constant()) { | 704 | 2.83k | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 2.83k | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 2.83k | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 2.83k | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 2.83k | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 2.83k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 2.83k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 2.83k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 2.83k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 2.83k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 2.83k | limbconst = | 715 | 2.83k | limbconst || | 716 | 2.83k | (prime_basis_limb.witness_index == | 717 | 2.83k | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 2.83k | if (!limbconst) { | 720 | 2.83k | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 2.83k | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 2.83k | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 2.83k | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 2.83k | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 2.83k | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 2.83k | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 2.83k | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 2.83k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 2.83k | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 2.83k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 2.83k | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 2.83k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 2.83k | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 2.83k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 2.83k | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 2.83k | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 2.83k | other.binary_basis_limbs[0].element.additive_constant); | 738 | 2.83k | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 2.83k | other.binary_basis_limbs[1].element.additive_constant); | 740 | 2.83k | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 2.83k | other.binary_basis_limbs[2].element.additive_constant); | 742 | 2.83k | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 2.83k | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 2.83k | uint32_t xp(prime_basis_limb.witness_index); | 746 | 2.83k | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 2.83k | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 2.83k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 2.83k | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 2.83k | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 2.83k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 2.83k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 2.83k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 2.83k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 2.83k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 2.83k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 2.83k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 2.83k | return result; | 762 | 2.83k | } | 763 | 2.83k | } | 764 | 7.21k | } | 765 | | | 766 | 4.38k | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 4.38k | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 4.38k | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 4.38k | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 4.38k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 4.38k | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 4.38k | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 4.38k | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 4.38k | return result; | 779 | 7.21k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmiERKS7_ Line | Count | Source | 577 | 26 | { | 578 | 26 | Builder* ctx = context ? context : other.context; | 579 | 26 | reduction_check(); | 580 | 26 | other.reduction_check(); | 581 | | | 582 | 26 | if (is_constant() && other.is_constant()) { | 583 | 0 | uint512_t left = get_value() % modulus_u512; | 584 | 0 | uint512_t right = other.get_value() % modulus_u512; | 585 | 0 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | |
| 587 | 0 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 0 | return result; | 590 | 0 | } | 591 | | | 592 | 26 | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 26 | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 26 | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 26 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 26 | uint256_t limb_1_maximum_value = | 632 | 26 | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 26 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 26 | uint256_t limb_2_maximum_value = | 637 | 26 | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 26 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 26 | uint256_t limb_3_maximum_value = | 641 | 26 | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 26 | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 28 | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 2 | constant_to_add += modulus_u512; | 655 | 2 | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 26 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 26 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 26 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 26 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 26 | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 26 | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 26 | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 26 | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 26 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 26 | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 26 | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 26 | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 26 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 26 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 26 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 26 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 26 | if constexpr (HasPlookup<Builder>) { | 702 | 26 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 26 | !is_constant() && !other.is_constant()) { | 704 | 26 | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 26 | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 26 | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 26 | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 26 | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 26 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 26 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 26 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 26 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 26 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 26 | limbconst = | 715 | 26 | limbconst || | 716 | 26 | (prime_basis_limb.witness_index == | 717 | 26 | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 26 | if (!limbconst) { | 720 | 26 | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 26 | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 26 | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 26 | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 26 | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 26 | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 26 | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 26 | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 26 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 26 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 26 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 26 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 26 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 26 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 26 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 26 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 26 | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 26 | other.binary_basis_limbs[0].element.additive_constant); | 738 | 26 | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 26 | other.binary_basis_limbs[1].element.additive_constant); | 740 | 26 | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 26 | other.binary_basis_limbs[2].element.additive_constant); | 742 | 26 | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 26 | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 26 | uint32_t xp(prime_basis_limb.witness_index); | 746 | 26 | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 26 | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 26 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 26 | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 26 | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 26 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 26 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 26 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 26 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 26 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 26 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 26 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 26 | return result; | 762 | 26 | } | 763 | 26 | } | 764 | 26 | } | 765 | | | 766 | 0 | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 0 | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 0 | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 0 | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 0 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 0 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 0 | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 0 | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 0 | return result; | 779 | 26 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmiERKS9_ Line | Count | Source | 577 | 162k | { | 578 | 162k | Builder* ctx = context ? context : other.context; | 579 | 162k | reduction_check(); | 580 | 162k | other.reduction_check(); | 581 | | | 582 | 162k | if (is_constant() && other.is_constant()) { | 583 | 432 | uint512_t left = get_value() % modulus_u512; | 584 | 432 | uint512_t right = other.get_value() % modulus_u512; | 585 | 432 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | | | 587 | 432 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 432 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 432 | return result; | 590 | 432 | } | 591 | | | 592 | 161k | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 161k | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 161k | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 161k | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 161k | uint256_t limb_1_maximum_value = | 632 | 161k | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 161k | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 161k | uint256_t limb_2_maximum_value = | 637 | 161k | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 161k | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 161k | uint256_t limb_3_maximum_value = | 641 | 161k | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 161k | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 333k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 171k | constant_to_add += modulus_u512; | 655 | 171k | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 161k | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 161k | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 161k | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 161k | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 161k | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 161k | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 161k | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 161k | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 161k | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 161k | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 161k | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 161k | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 161k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 161k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 161k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 161k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 161k | if constexpr (HasPlookup<Builder>) { | 702 | 161k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 161k | !is_constant() && !other.is_constant()) { | 704 | 63.6k | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 63.6k | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 63.6k | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 63.6k | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 63.6k | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 63.6k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 63.6k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 63.6k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 63.6k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 63.6k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 63.6k | limbconst = | 715 | 63.6k | limbconst || | 716 | 63.6k | (prime_basis_limb.witness_index == | 717 | 63.6k | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 63.6k | if (!limbconst) { | 720 | 63.6k | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 63.6k | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 63.6k | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 63.6k | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 63.6k | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 63.6k | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 63.6k | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 63.6k | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 63.6k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 63.6k | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 63.6k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 63.6k | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 63.6k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 63.6k | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 63.6k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 63.6k | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 63.6k | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 63.6k | other.binary_basis_limbs[0].element.additive_constant); | 738 | 63.6k | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 63.6k | other.binary_basis_limbs[1].element.additive_constant); | 740 | 63.6k | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 63.6k | other.binary_basis_limbs[2].element.additive_constant); | 742 | 63.6k | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 63.6k | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 63.6k | uint32_t xp(prime_basis_limb.witness_index); | 746 | 63.6k | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 63.6k | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 63.6k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 63.6k | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 63.6k | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 63.6k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 63.6k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 63.6k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 63.6k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 63.6k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 63.6k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 63.6k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 63.6k | return result; | 762 | 63.6k | } | 763 | 63.6k | } | 764 | 161k | } | 765 | | | 766 | 97.9k | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 97.9k | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 97.9k | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 97.9k | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 97.9k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 97.9k | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 97.9k | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 97.9k | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 97.9k | return result; | 779 | 161k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmiERKS9_ Line | Count | Source | 577 | 576 | { | 578 | 576 | Builder* ctx = context ? context : other.context; | 579 | 576 | reduction_check(); | 580 | 576 | other.reduction_check(); | 581 | | | 582 | 576 | if (is_constant() && other.is_constant()) { | 583 | 0 | uint512_t left = get_value() % modulus_u512; | 584 | 0 | uint512_t right = other.get_value() % modulus_u512; | 585 | 0 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | |
| 587 | 0 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 0 | return result; | 590 | 0 | } | 591 | | | 592 | 576 | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 576 | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 576 | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 576 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 576 | uint256_t limb_1_maximum_value = | 632 | 576 | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 576 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 576 | uint256_t limb_2_maximum_value = | 637 | 576 | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 576 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 576 | uint256_t limb_3_maximum_value = | 641 | 576 | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 576 | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 576 | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 0 | constant_to_add += modulus_u512; | 655 | 0 | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 576 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 576 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 576 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 576 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 576 | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 576 | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 576 | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 576 | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 576 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 576 | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 576 | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 576 | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 576 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 576 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 576 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 576 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 576 | if constexpr (HasPlookup<Builder>) { | 702 | 576 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 576 | !is_constant() && !other.is_constant()) { | 704 | 576 | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 576 | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 576 | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 576 | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 576 | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 576 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 576 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 576 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 576 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 576 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 576 | limbconst = | 715 | 576 | limbconst || | 716 | 576 | (prime_basis_limb.witness_index == | 717 | 576 | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 576 | if (!limbconst) { | 720 | 576 | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 576 | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 576 | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 576 | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 576 | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 576 | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 576 | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 576 | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 576 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 576 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 576 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 576 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 576 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 576 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 576 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 576 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 576 | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 576 | other.binary_basis_limbs[0].element.additive_constant); | 738 | 576 | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 576 | other.binary_basis_limbs[1].element.additive_constant); | 740 | 576 | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 576 | other.binary_basis_limbs[2].element.additive_constant); | 742 | 576 | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 576 | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 576 | uint32_t xp(prime_basis_limb.witness_index); | 746 | 576 | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 576 | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 576 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 576 | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 576 | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 576 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 576 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 576 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 576 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 576 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 576 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 576 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 576 | return result; | 762 | 576 | } | 763 | 576 | } | 764 | 576 | } | 765 | | | 766 | 0 | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 0 | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 0 | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 0 | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 0 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 0 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 0 | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 0 | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 0 | return result; | 779 | 576 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmiERKS7_ Line | Count | Source | 577 | 11.4k | { | 578 | 11.4k | Builder* ctx = context ? context : other.context; | 579 | 11.4k | reduction_check(); | 580 | 11.4k | other.reduction_check(); | 581 | | | 582 | 11.4k | if (is_constant() && other.is_constant()) { | 583 | 50 | uint512_t left = get_value() % modulus_u512; | 584 | 50 | uint512_t right = other.get_value() % modulus_u512; | 585 | 50 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | | | 587 | 50 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 50 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 50 | return result; | 590 | 50 | } | 591 | | | 592 | 11.3k | if (other.is_constant()) { | 593 | 15 | uint512_t right = other.get_value() % modulus_u512; | 594 | 15 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 15 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 15 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 11.3k | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 11.3k | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 11.3k | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 11.3k | uint256_t limb_1_maximum_value = | 632 | 11.3k | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 11.3k | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 11.3k | uint256_t limb_2_maximum_value = | 637 | 11.3k | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 11.3k | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 11.3k | uint256_t limb_3_maximum_value = | 641 | 11.3k | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 11.3k | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 23.0k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 11.6k | constant_to_add += modulus_u512; | 655 | 11.6k | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 11.3k | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 11.3k | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 11.3k | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 11.3k | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 11.3k | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 11.3k | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 11.3k | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 11.3k | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 11.3k | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 11.3k | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 11.3k | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 11.3k | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 11.3k | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 11.3k | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 11.3k | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 11.3k | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 11.3k | if constexpr (HasPlookup<Builder>) { | 702 | 11.3k | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 11.3k | !is_constant() && !other.is_constant()) { | 704 | 4.50k | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 4.50k | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 4.50k | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 4.50k | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 4.50k | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 4.50k | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 4.50k | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 4.50k | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 4.50k | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 4.50k | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 4.50k | limbconst = | 715 | 4.50k | limbconst || | 716 | 4.50k | (prime_basis_limb.witness_index == | 717 | 4.50k | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 4.50k | if (!limbconst) { | 720 | 4.50k | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 4.50k | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 4.50k | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 4.50k | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 4.50k | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 4.50k | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 4.50k | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 4.50k | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 4.50k | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 4.50k | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 4.50k | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 4.50k | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 4.50k | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 4.50k | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 4.50k | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 4.50k | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 4.50k | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 4.50k | other.binary_basis_limbs[0].element.additive_constant); | 738 | 4.50k | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 4.50k | other.binary_basis_limbs[1].element.additive_constant); | 740 | 4.50k | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 4.50k | other.binary_basis_limbs[2].element.additive_constant); | 742 | 4.50k | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 4.50k | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 4.50k | uint32_t xp(prime_basis_limb.witness_index); | 746 | 4.50k | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 4.50k | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 4.50k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 4.50k | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 4.50k | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 4.50k | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 4.50k | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 4.50k | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 4.50k | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 4.50k | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 4.50k | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 4.50k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 4.50k | return result; | 762 | 4.50k | } | 763 | 4.50k | } | 764 | 11.3k | } | 765 | | | 766 | 6.83k | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 6.83k | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 6.83k | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 6.83k | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 6.83k | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 6.83k | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 6.83k | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 6.83k | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 6.83k | return result; | 779 | 11.3k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmiERKS7_ Line | Count | Source | 577 | 20 | { | 578 | 20 | Builder* ctx = context ? context : other.context; | 579 | 20 | reduction_check(); | 580 | 20 | other.reduction_check(); | 581 | | | 582 | 20 | if (is_constant() && other.is_constant()) { | 583 | 0 | uint512_t left = get_value() % modulus_u512; | 584 | 0 | uint512_t right = other.get_value() % modulus_u512; | 585 | 0 | uint512_t out = (left + modulus_u512 - right) % modulus_u512; | 586 | |
| 587 | 0 | auto result = bigfield(ctx, uint256_t(out.lo)); | 588 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 589 | 0 | return result; | 590 | 0 | } | 591 | | | 592 | 20 | if (other.is_constant()) { | 593 | 0 | uint512_t right = other.get_value() % modulus_u512; | 594 | 0 | uint512_t neg_right = (modulus_u512 - right) % modulus_u512; | 595 | 0 | return operator+(bigfield(ctx, uint256_t(neg_right.lo))); | 596 | 0 | } | 597 | | | 598 | | /** | 599 | | * Plookup bigfield subtractoin | 600 | | * | 601 | | * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0) | 602 | | * This is in addition to the regular addition gate | 603 | | * | 604 | | * We can arrange our wires in memory like this: | 605 | | * | 606 | | * | 1 | 2 | 3 | 4 | | 607 | | * |-----|-----|-----|-----| | 608 | | * | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) | 609 | | * | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0) | 610 | | * | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0) | 611 | | * | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0) | 612 | | * | 613 | | **/ | 614 | | | 615 | 20 | bigfield result(ctx); | 616 | | | 617 | | /** | 618 | | * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb | 619 | | * | 620 | | * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from | 621 | | * the next significant limb to ensure each limb value is positive? | 622 | | * | 623 | | * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result | 624 | | **/ | 625 | 20 | uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value; | 626 | | | 627 | | // Compute maximum shift factor for limb_0 | 628 | 20 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 629 | | | 630 | | // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow | 631 | 20 | uint256_t limb_1_maximum_value = | 632 | 20 | other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 633 | | | 634 | | // repeat the above for the remaining limbs | 635 | 20 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 636 | 20 | uint256_t limb_2_maximum_value = | 637 | 20 | other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 638 | 20 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 639 | | | 640 | 20 | uint256_t limb_3_maximum_value = | 641 | 20 | other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 642 | | | 643 | | /** | 644 | | * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0 | 645 | | * | 646 | | * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`. | 647 | | * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive | 648 | | * | 649 | | * Start by setting constant_to_add = p | 650 | | **/ | 651 | 20 | uint512_t constant_to_add = modulus_u512; | 652 | | // add a large enough multiple of p to not get negative result in subtraction | 653 | 40 | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 654 | 20 | constant_to_add += modulus_u512; | 655 | 20 | } | 656 | | | 657 | | /** | 658 | | * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive | 659 | | * | 660 | | * t3 represents the value we are BORROWING from constant_to_add.limb[3] | 661 | | * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1], | 662 | | *constant_to_add.limb[0] | 663 | | * | 664 | | * i.e. The net value we add to `constant_to_add` is 0. We must ensure that: | 665 | | * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2) | 666 | | * | 667 | | * e.g. the value we borrow to produce t0 is subtracted from t1, | 668 | | * the value we borrow from t1 is subtracted from t2 | 669 | | * the value we borrow from t2 is equal to t3 | 670 | | **/ | 671 | 20 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 672 | 20 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 673 | 20 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 674 | 20 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 675 | | | 676 | | /** | 677 | | * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result | 678 | | *limb is positive | 679 | | **/ | 680 | 20 | uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0; | 681 | 20 | uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1; | 682 | 20 | uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2; | 683 | 20 | uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3; | 684 | | | 685 | | /** | 686 | | * Update the maximum possible value of the result. We assume here that (*this.value) = 0 | 687 | | **/ | 688 | 20 | result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0; | 689 | 20 | result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1; | 690 | 20 | result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2; | 691 | 20 | result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3; | 692 | | | 693 | | /** | 694 | | * Compute the binary basis limbs of our result | 695 | | **/ | 696 | 20 | result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0); | 697 | 20 | result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1); | 698 | 20 | result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2); | 699 | 20 | result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3); | 700 | | | 701 | 20 | if constexpr (HasPlookup<Builder>) { | 702 | 20 | if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 && | 703 | 20 | !is_constant() && !other.is_constant()) { | 704 | 20 | bool limbconst = result.binary_basis_limbs[0].element.is_constant(); | 705 | 20 | limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant(); | 706 | 20 | limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant(); | 707 | 20 | limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant(); | 708 | 20 | limbconst = limbconst || prime_basis_limb.is_constant(); | 709 | 20 | limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant(); | 710 | 20 | limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant(); | 711 | 20 | limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant(); | 712 | 20 | limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant(); | 713 | 20 | limbconst = limbconst || other.prime_basis_limb.is_constant(); | 714 | 20 | limbconst = | 715 | 20 | limbconst || | 716 | 20 | (prime_basis_limb.witness_index == | 717 | 20 | other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we | 718 | | // need to compare the actual indices, not normalized ones | 719 | 20 | if (!limbconst) { | 720 | 20 | std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index, | 721 | 20 | binary_basis_limbs[0].element.multiplicative_constant }; | 722 | 20 | std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index, | 723 | 20 | binary_basis_limbs[1].element.multiplicative_constant }; | 724 | 20 | std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index, | 725 | 20 | binary_basis_limbs[2].element.multiplicative_constant }; | 726 | 20 | std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index, | 727 | 20 | binary_basis_limbs[3].element.multiplicative_constant }; | 728 | 20 | std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index, | 729 | 20 | other.binary_basis_limbs[0].element.multiplicative_constant }; | 730 | 20 | std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index, | 731 | 20 | other.binary_basis_limbs[1].element.multiplicative_constant }; | 732 | 20 | std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index, | 733 | 20 | other.binary_basis_limbs[2].element.multiplicative_constant }; | 734 | 20 | std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index, | 735 | 20 | other.binary_basis_limbs[3].element.multiplicative_constant }; | 736 | 20 | bb::fr c0(result.binary_basis_limbs[0].element.additive_constant - | 737 | 20 | other.binary_basis_limbs[0].element.additive_constant); | 738 | 20 | bb::fr c1(result.binary_basis_limbs[1].element.additive_constant - | 739 | 20 | other.binary_basis_limbs[1].element.additive_constant); | 740 | 20 | bb::fr c2(result.binary_basis_limbs[2].element.additive_constant - | 741 | 20 | other.binary_basis_limbs[2].element.additive_constant); | 742 | 20 | bb::fr c3(result.binary_basis_limbs[3].element.additive_constant - | 743 | 20 | other.binary_basis_limbs[3].element.additive_constant); | 744 | | | 745 | 20 | uint32_t xp(prime_basis_limb.witness_index); | 746 | 20 | uint32_t yp(other.prime_basis_limb.witness_index); | 747 | 20 | bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant); | 748 | 20 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 749 | 20 | cp += bb::fr(constant_to_add_mod_p.lo); | 750 | | | 751 | 20 | const auto output_witnesses = ctx->evaluate_non_native_field_subtraction( | 752 | 20 | { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp }); | 753 | | | 754 | 20 | result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]); | 755 | 20 | result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]); | 756 | 20 | result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]); | 757 | 20 | result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]); | 758 | 20 | result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]); | 759 | | | 760 | 20 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 761 | 20 | return result; | 762 | 20 | } | 763 | 20 | } | 764 | 20 | } | 765 | | | 766 | 0 | result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element; | 767 | 0 | result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element; | 768 | 0 | result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element; | 769 | 0 | result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element; | 770 | | | 771 | | /** | 772 | | * Compute the prime basis limb of the result | 773 | | **/ | 774 | 0 | uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus; | 775 | 0 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 776 | 0 | result.prime_basis_limb = prime_basis_limb + prime_basis_to_add; | 777 | 0 | result.prime_basis_limb -= other.prime_basis_limb; | 778 | 0 | return result; | 779 | 20 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmiERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmiERKS9_ |
780 | | |
781 | | /** |
782 | | * Evaluate a non-native field multiplication: (a * b = c mod p) where p == target_basis.modulus |
783 | | * |
784 | | * We compute quotient term `q` and remainder `c` and evaluate that: |
785 | | * |
786 | | * a * b - q * p - c = 0 mod modulus_u512 (binary basis modulus, currently 2**272) |
787 | | * a * b - q * p - c = 0 mod circuit modulus |
788 | | **/ |
789 | | template <typename Builder, typename T> |
790 | | bigfield<Builder, T> bigfield<Builder, T>::operator*(const bigfield& other) const |
791 | 218k | { |
792 | | // First we do basic reduction checks of individual elements |
793 | 218k | reduction_check(); |
794 | 218k | other.reduction_check(); |
795 | 218k | Builder* ctx = context ? context : other.context; |
796 | | // Now we can actually compute the quotient and remainder values |
797 | 218k | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); |
798 | 218k | bigfield remainder; |
799 | 218k | bigfield quotient; |
800 | | // If operands are constant, define result as a constant value and return |
801 | 218k | if (is_constant() && other.is_constant()) { |
802 | 4.13k | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); |
803 | 4.13k | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
804 | 4.13k | return remainder; |
805 | 214k | } else { |
806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s |
807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions |
808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS |
809 | | |
810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce |
811 | | // accordingly |
812 | 214k | auto [reduction_required, num_quotient_bits] = |
813 | 214k | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); |
814 | 214k | if (reduction_required) { |
815 | 1 | if (get_maximum_value() > other.get_maximum_value()) { |
816 | 0 | self_reduce(); |
817 | 1 | } else { |
818 | 1 | other.self_reduce(); |
819 | 1 | } |
820 | 1 | return (*this).operator*(other); |
821 | 1 | } |
822 | 214k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
823 | 214k | remainder = create_from_u512_as_witness(ctx, remainder_value); |
824 | 214k | }; |
825 | | |
826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder |
827 | 214k | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); |
828 | | |
829 | 214k | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
830 | 214k | return remainder; |
831 | 218k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmlERKS6_ Line | Count | Source | 791 | 212k | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 212k | reduction_check(); | 794 | 212k | other.reduction_check(); | 795 | 212k | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 212k | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 212k | bigfield remainder; | 799 | 212k | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 212k | if (is_constant() && other.is_constant()) { | 802 | 4.12k | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 4.12k | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 4.12k | return remainder; | 805 | 208k | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 208k | auto [reduction_required, num_quotient_bits] = | 813 | 208k | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 208k | if (reduction_required) { | 815 | 1 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 1 | } else { | 818 | 1 | other.self_reduce(); | 819 | 1 | } | 820 | 1 | return (*this).operator*(other); | 821 | 1 | } | 822 | 208k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 208k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 208k | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 208k | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 208k | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 208k | return remainder; | 831 | 212k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmlERKS6_ Line | Count | Source | 791 | 38 | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 38 | reduction_check(); | 794 | 38 | other.reduction_check(); | 795 | 38 | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 38 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 38 | bigfield remainder; | 799 | 38 | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 38 | if (is_constant() && other.is_constant()) { | 802 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 0 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 0 | return remainder; | 805 | 38 | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 38 | auto [reduction_required, num_quotient_bits] = | 813 | 38 | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 38 | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 38 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 38 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 38 | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 38 | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 38 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 38 | return remainder; | 831 | 38 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmlERKS8_ Line | Count | Source | 791 | 20 | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 20 | reduction_check(); | 794 | 20 | other.reduction_check(); | 795 | 20 | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 20 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 20 | bigfield remainder; | 799 | 20 | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 20 | if (is_constant() && other.is_constant()) { | 802 | 4 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 4 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 4 | return remainder; | 805 | 16 | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 16 | auto [reduction_required, num_quotient_bits] = | 813 | 16 | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 16 | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 16 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 16 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 16 | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 16 | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 16 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 16 | return remainder; | 831 | 20 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmlERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmlERKS7_ Line | Count | Source | 791 | 246 | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 246 | reduction_check(); | 794 | 246 | other.reduction_check(); | 795 | 246 | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 246 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 246 | bigfield remainder; | 799 | 246 | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 246 | if (is_constant() && other.is_constant()) { | 802 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 0 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 0 | return remainder; | 805 | 246 | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 246 | auto [reduction_required, num_quotient_bits] = | 813 | 246 | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 246 | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 246 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 246 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 246 | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 246 | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 246 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 246 | return remainder; | 831 | 246 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmlERKS7_ Line | Count | Source | 791 | 1 | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 1 | reduction_check(); | 794 | 1 | other.reduction_check(); | 795 | 1 | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 1 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 1 | bigfield remainder; | 799 | 1 | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 1 | if (is_constant() && other.is_constant()) { | 802 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 0 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 0 | return remainder; | 805 | 1 | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 1 | auto [reduction_required, num_quotient_bits] = | 813 | 1 | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 1 | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 1 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 1 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 1 | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 1 | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 1 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 1 | return remainder; | 831 | 1 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmlERKS9_ Line | Count | Source | 791 | 5.90k | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 5.90k | reduction_check(); | 794 | 5.90k | other.reduction_check(); | 795 | 5.90k | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 5.90k | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 5.90k | bigfield remainder; | 799 | 5.90k | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 5.90k | if (is_constant() && other.is_constant()) { | 802 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 0 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 0 | return remainder; | 805 | 5.90k | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 5.90k | auto [reduction_required, num_quotient_bits] = | 813 | 5.90k | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 5.90k | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 5.90k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 5.90k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 5.90k | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 5.90k | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 5.90k | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 5.90k | return remainder; | 831 | 5.90k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmlERKS9_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmlERKS7_ Line | Count | Source | 791 | 45 | { | 792 | | // First we do basic reduction checks of individual elements | 793 | 45 | reduction_check(); | 794 | 45 | other.reduction_check(); | 795 | 45 | Builder* ctx = context ? context : other.context; | 796 | | // Now we can actually compute the quotient and remainder values | 797 | 45 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {}); | 798 | 45 | bigfield remainder; | 799 | 45 | bigfield quotient; | 800 | | // If operands are constant, define result as a constant value and return | 801 | 45 | if (is_constant() && other.is_constant()) { | 802 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 803 | 0 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 804 | 0 | return remainder; | 805 | 45 | } else { | 806 | | // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s | 807 | | // hence the second constructor call is with can_overflow=false. This will allow using r in more additions | 808 | | // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS | 809 | | | 810 | | // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce | 811 | | // accordingly | 812 | 45 | auto [reduction_required, num_quotient_bits] = | 813 | 45 | get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {}); | 814 | 45 | if (reduction_required) { | 815 | 0 | if (get_maximum_value() > other.get_maximum_value()) { | 816 | 0 | self_reduce(); | 817 | 0 | } else { | 818 | 0 | other.self_reduce(); | 819 | 0 | } | 820 | 0 | return (*this).operator*(other); | 821 | 0 | } | 822 | 45 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 823 | 45 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 824 | 45 | }; | 825 | | | 826 | | // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder | 827 | 45 | unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder }); | 828 | | | 829 | 45 | remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 830 | 45 | return remainder; | 831 | 45 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmlERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmlERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmlERKS9_ |
832 | | |
833 | | /** |
834 | | * Division operator. Create constraints for b!=0 by default. If you need a variant |
835 | | *without the zero check, use div_without_denominator_check. |
836 | | * |
837 | | * To evaluate (a / b = c mod p), we instead evaluate (c * b = a mod p). |
838 | | **/ |
839 | | template <typename Builder, typename T> |
840 | | bigfield<Builder, T> bigfield<Builder, T>::operator/(const bigfield& other) const |
841 | 4.95k | { |
842 | | |
843 | 4.95k | return internal_div({ *this }, other, true); |
844 | 4.95k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEdvERKS6_ Line | Count | Source | 841 | 4.93k | { | 842 | | | 843 | 4.93k | return internal_div({ *this }, other, true); | 844 | 4.93k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEdvERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEdvERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EdvERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEdvERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEdvERKS7_ Line | Count | Source | 841 | 12 | { | 842 | | | 843 | 12 | return internal_div({ *this }, other, true); | 844 | 12 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEdvERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEdvERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEdvERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEdvERKS7_ Line | Count | Source | 841 | 8 | { | 842 | | | 843 | 8 | return internal_div({ *this }, other, true); | 844 | 8 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEdvERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEdvERKS9_ |
845 | | /** |
846 | | * @brief Create constraints for summing these terms |
847 | | * |
848 | | * @tparam Builder |
849 | | * @tparam T |
850 | | * @param terms |
851 | | * @return The sum of terms |
852 | | */ |
853 | | template <typename Builder, typename T> |
854 | | bigfield<Builder, T> bigfield<Builder, T>::sum(const std::vector<bigfield>& terms) |
855 | 0 | { |
856 | 0 | ASSERT(terms.size() > 0); |
857 | | |
858 | 0 | if (terms.size() == 1) { |
859 | 0 | return terms[0]; |
860 | 0 | } |
861 | | |
862 | 0 | bigfield acc = terms[0]; |
863 | 0 | for (size_t i = 1; i < (terms.size() + 1) / 2; i++) { |
864 | 0 | acc = acc.add_two(terms[2 * i - 1], terms[2 * i]); |
865 | 0 | } |
866 | 0 | if ((terms.size() & 1) == 0) { |
867 | 0 | acc += terms[terms.size() - 1]; |
868 | 0 | } |
869 | 0 | return acc; |
870 | 0 | } Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE |
871 | | |
872 | | /** |
873 | | * Division of a sum with an optional check if divisor is zero. Should not be used outside of class. |
874 | | * |
875 | | * @param numerators Vector of numerators |
876 | | * @param denominator Denominator |
877 | | * @param check_for_zero If the zero check should be enabled |
878 | | * |
879 | | * @return The result of division |
880 | | * */ |
881 | | template <typename Builder, typename T> |
882 | | bigfield<Builder, T> bigfield<Builder, T>::internal_div(const std::vector<bigfield>& numerators, |
883 | | const bigfield& denominator, |
884 | | bool check_for_zero) |
885 | 118k | { |
886 | 118k | if (numerators.size() == 0) { |
887 | 1 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); |
888 | 1 | } |
889 | | |
890 | 118k | denominator.reduction_check(); |
891 | 118k | Builder* ctx = denominator.context; |
892 | 118k | uint512_t numerator_values(0); |
893 | 118k | bool numerator_constant = true; |
894 | 118k | OriginTag tag = denominator.get_origin_tag(); |
895 | 165k | for (const auto& numerator_element : numerators) { |
896 | 165k | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; |
897 | 165k | numerator_element.reduction_check(); |
898 | 165k | numerator_values += numerator_element.get_value(); |
899 | 165k | numerator_constant = numerator_constant && (numerator_element.is_constant()); |
900 | 165k | tag = OriginTag(tag, numerator_element.get_origin_tag()); |
901 | 165k | } |
902 | | |
903 | | // a / b = c |
904 | | // => c * b = a mod p |
905 | 118k | const uint1024_t left = uint1024_t(numerator_values); |
906 | 118k | const uint1024_t right = uint1024_t(denominator.get_value()); |
907 | 118k | const uint1024_t modulus(target_basis.modulus); |
908 | | // We don't want to trigger the uint assert |
909 | 118k | uint512_t inverse_value(0); |
910 | 118k | if (right.lo != uint512_t(0)) { |
911 | 118k | inverse_value = right.lo.invmod(target_basis.modulus).lo; |
912 | 118k | } |
913 | 118k | uint1024_t inverse_1024(inverse_value); |
914 | 118k | inverse_value = ((left * inverse_1024) % modulus).lo; |
915 | | |
916 | 118k | const uint1024_t quotient_1024 = |
917 | 118k | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; |
918 | 118k | const uint512_t quotient_value = quotient_1024.lo; |
919 | | |
920 | 118k | bigfield inverse; |
921 | 118k | bigfield quotient; |
922 | 118k | if (numerator_constant && denominator.is_constant()) { |
923 | 76 | inverse = bigfield(ctx, uint256_t(inverse_value)); |
924 | 76 | inverse.set_origin_tag(tag); |
925 | 76 | return inverse; |
926 | 118k | } else { |
927 | | // We only add the check if the result is non-constant |
928 | 118k | std::vector<uint1024_t> numerator_max; |
929 | 165k | for (const auto& n : numerators) { |
930 | 165k | numerator_max.push_back(n.get_maximum_value()); |
931 | 165k | } |
932 | | |
933 | 118k | auto [reduction_required, num_quotient_bits] = |
934 | 118k | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, |
935 | 118k | { denominator.get_maximum_value() }, |
936 | 118k | { unreduced_zero() }, |
937 | 118k | numerator_max); |
938 | 118k | if (reduction_required) { |
939 | |
|
940 | 0 | denominator.self_reduce(); |
941 | 0 | return internal_div(numerators, denominator, check_for_zero); |
942 | 0 | } |
943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice |
944 | 118k | if (check_for_zero) { |
945 | 4.88k | denominator.assert_is_not_equal(zero()); |
946 | 4.88k | } |
947 | | |
948 | 118k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
949 | 118k | inverse = create_from_u512_as_witness(ctx, inverse_value); |
950 | 118k | } |
951 | | |
952 | 118k | inverse.set_origin_tag(tag); |
953 | 118k | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); |
954 | 118k | return inverse; |
955 | 118k | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b Line | Count | Source | 885 | 106k | { | 886 | 106k | if (numerators.size() == 0) { | 887 | 1 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 1 | } | 889 | | | 890 | 106k | denominator.reduction_check(); | 891 | 106k | Builder* ctx = denominator.context; | 892 | 106k | uint512_t numerator_values(0); | 893 | 106k | bool numerator_constant = true; | 894 | 106k | OriginTag tag = denominator.get_origin_tag(); | 895 | 153k | for (const auto& numerator_element : numerators) { | 896 | 153k | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 153k | numerator_element.reduction_check(); | 898 | 153k | numerator_values += numerator_element.get_value(); | 899 | 153k | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 153k | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 153k | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 106k | const uint1024_t left = uint1024_t(numerator_values); | 906 | 106k | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 106k | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 106k | uint512_t inverse_value(0); | 910 | 106k | if (right.lo != uint512_t(0)) { | 911 | 106k | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 106k | } | 913 | 106k | uint1024_t inverse_1024(inverse_value); | 914 | 106k | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 106k | const uint1024_t quotient_1024 = | 917 | 106k | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 106k | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 106k | bigfield inverse; | 921 | 106k | bigfield quotient; | 922 | 106k | if (numerator_constant && denominator.is_constant()) { | 923 | 76 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 76 | inverse.set_origin_tag(tag); | 925 | 76 | return inverse; | 926 | 105k | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 105k | std::vector<uint1024_t> numerator_max; | 929 | 153k | for (const auto& n : numerators) { | 930 | 153k | numerator_max.push_back(n.get_maximum_value()); | 931 | 153k | } | 932 | | | 933 | 105k | auto [reduction_required, num_quotient_bits] = | 934 | 105k | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 105k | { denominator.get_maximum_value() }, | 936 | 105k | { unreduced_zero() }, | 937 | 105k | numerator_max); | 938 | 105k | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 105k | if (check_for_zero) { | 945 | 4.86k | denominator.assert_is_not_equal(zero()); | 946 | 4.86k | } | 947 | | | 948 | 105k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 105k | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 105k | } | 951 | | | 952 | 105k | inverse.set_origin_tag(tag); | 953 | 105k | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 105k | return inverse; | 955 | 106k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS8_SaIS8_EERKS8_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b Line | Count | Source | 885 | 488 | { | 886 | 488 | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 488 | denominator.reduction_check(); | 891 | 488 | Builder* ctx = denominator.context; | 892 | 488 | uint512_t numerator_values(0); | 893 | 488 | bool numerator_constant = true; | 894 | 488 | OriginTag tag = denominator.get_origin_tag(); | 895 | 494 | for (const auto& numerator_element : numerators) { | 896 | 494 | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 494 | numerator_element.reduction_check(); | 898 | 494 | numerator_values += numerator_element.get_value(); | 899 | 494 | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 494 | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 494 | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 488 | const uint1024_t left = uint1024_t(numerator_values); | 906 | 488 | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 488 | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 488 | uint512_t inverse_value(0); | 910 | 488 | if (right.lo != uint512_t(0)) { | 911 | 488 | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 488 | } | 913 | 488 | uint1024_t inverse_1024(inverse_value); | 914 | 488 | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 488 | const uint1024_t quotient_1024 = | 917 | 488 | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 488 | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 488 | bigfield inverse; | 921 | 488 | bigfield quotient; | 922 | 488 | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 488 | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 488 | std::vector<uint1024_t> numerator_max; | 929 | 494 | for (const auto& n : numerators) { | 930 | 494 | numerator_max.push_back(n.get_maximum_value()); | 931 | 494 | } | 932 | | | 933 | 488 | auto [reduction_required, num_quotient_bits] = | 934 | 488 | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 488 | { denominator.get_maximum_value() }, | 936 | 488 | { unreduced_zero() }, | 937 | 488 | numerator_max); | 938 | 488 | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 488 | if (check_for_zero) { | 945 | 0 | denominator.assert_is_not_equal(zero()); | 946 | 0 | } | 947 | | | 948 | 488 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 488 | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 488 | } | 951 | | | 952 | 488 | inverse.set_origin_tag(tag); | 953 | 488 | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 488 | return inverse; | 955 | 488 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b Line | Count | Source | 885 | 14 | { | 886 | 14 | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 14 | denominator.reduction_check(); | 891 | 14 | Builder* ctx = denominator.context; | 892 | 14 | uint512_t numerator_values(0); | 893 | 14 | bool numerator_constant = true; | 894 | 14 | OriginTag tag = denominator.get_origin_tag(); | 895 | 14 | for (const auto& numerator_element : numerators) { | 896 | 14 | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 14 | numerator_element.reduction_check(); | 898 | 14 | numerator_values += numerator_element.get_value(); | 899 | 14 | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 14 | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 14 | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 14 | const uint1024_t left = uint1024_t(numerator_values); | 906 | 14 | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 14 | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 14 | uint512_t inverse_value(0); | 910 | 14 | if (right.lo != uint512_t(0)) { | 911 | 14 | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 14 | } | 913 | 14 | uint1024_t inverse_1024(inverse_value); | 914 | 14 | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 14 | const uint1024_t quotient_1024 = | 917 | 14 | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 14 | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 14 | bigfield inverse; | 921 | 14 | bigfield quotient; | 922 | 14 | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 14 | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 14 | std::vector<uint1024_t> numerator_max; | 929 | 14 | for (const auto& n : numerators) { | 930 | 14 | numerator_max.push_back(n.get_maximum_value()); | 931 | 14 | } | 932 | | | 933 | 14 | auto [reduction_required, num_quotient_bits] = | 934 | 14 | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 14 | { denominator.get_maximum_value() }, | 936 | 14 | { unreduced_zero() }, | 937 | 14 | numerator_max); | 938 | 14 | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 14 | if (check_for_zero) { | 945 | 12 | denominator.assert_is_not_equal(zero()); | 946 | 12 | } | 947 | | | 948 | 14 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 14 | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 14 | } | 951 | | | 952 | 14 | inverse.set_origin_tag(tag); | 953 | 14 | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 14 | return inverse; | 955 | 14 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b Line | Count | Source | 885 | 10.9k | { | 886 | 10.9k | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 10.9k | denominator.reduction_check(); | 891 | 10.9k | Builder* ctx = denominator.context; | 892 | 10.9k | uint512_t numerator_values(0); | 893 | 10.9k | bool numerator_constant = true; | 894 | 10.9k | OriginTag tag = denominator.get_origin_tag(); | 895 | 11.0k | for (const auto& numerator_element : numerators) { | 896 | 11.0k | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 11.0k | numerator_element.reduction_check(); | 898 | 11.0k | numerator_values += numerator_element.get_value(); | 899 | 11.0k | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 11.0k | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 11.0k | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 10.9k | const uint1024_t left = uint1024_t(numerator_values); | 906 | 10.9k | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 10.9k | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 10.9k | uint512_t inverse_value(0); | 910 | 10.9k | if (right.lo != uint512_t(0)) { | 911 | 10.9k | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 10.9k | } | 913 | 10.9k | uint1024_t inverse_1024(inverse_value); | 914 | 10.9k | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 10.9k | const uint1024_t quotient_1024 = | 917 | 10.9k | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 10.9k | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 10.9k | bigfield inverse; | 921 | 10.9k | bigfield quotient; | 922 | 10.9k | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 10.9k | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 10.9k | std::vector<uint1024_t> numerator_max; | 929 | 11.0k | for (const auto& n : numerators) { | 930 | 11.0k | numerator_max.push_back(n.get_maximum_value()); | 931 | 11.0k | } | 932 | | | 933 | 10.9k | auto [reduction_required, num_quotient_bits] = | 934 | 10.9k | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 10.9k | { denominator.get_maximum_value() }, | 936 | 10.9k | { unreduced_zero() }, | 937 | 10.9k | numerator_max); | 938 | 10.9k | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 10.9k | if (check_for_zero) { | 945 | 0 | denominator.assert_is_not_equal(zero()); | 946 | 0 | } | 947 | | | 948 | 10.9k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 10.9k | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 10.9k | } | 951 | | | 952 | 10.9k | inverse.set_origin_tag(tag); | 953 | 10.9k | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 10.9k | return inverse; | 955 | 10.9k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b Line | Count | Source | 885 | 288 | { | 886 | 288 | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 288 | denominator.reduction_check(); | 891 | 288 | Builder* ctx = denominator.context; | 892 | 288 | uint512_t numerator_values(0); | 893 | 288 | bool numerator_constant = true; | 894 | 288 | OriginTag tag = denominator.get_origin_tag(); | 895 | 288 | for (const auto& numerator_element : numerators) { | 896 | 288 | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 288 | numerator_element.reduction_check(); | 898 | 288 | numerator_values += numerator_element.get_value(); | 899 | 288 | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 288 | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 288 | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 288 | const uint1024_t left = uint1024_t(numerator_values); | 906 | 288 | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 288 | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 288 | uint512_t inverse_value(0); | 910 | 288 | if (right.lo != uint512_t(0)) { | 911 | 288 | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 288 | } | 913 | 288 | uint1024_t inverse_1024(inverse_value); | 914 | 288 | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 288 | const uint1024_t quotient_1024 = | 917 | 288 | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 288 | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 288 | bigfield inverse; | 921 | 288 | bigfield quotient; | 922 | 288 | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 288 | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 288 | std::vector<uint1024_t> numerator_max; | 929 | 288 | for (const auto& n : numerators) { | 930 | 288 | numerator_max.push_back(n.get_maximum_value()); | 931 | 288 | } | 932 | | | 933 | 288 | auto [reduction_required, num_quotient_bits] = | 934 | 288 | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 288 | { denominator.get_maximum_value() }, | 936 | 288 | { unreduced_zero() }, | 937 | 288 | numerator_max); | 938 | 288 | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 288 | if (check_for_zero) { | 945 | 0 | denominator.assert_is_not_equal(zero()); | 946 | 0 | } | 947 | | | 948 | 288 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 288 | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 288 | } | 951 | | | 952 | 288 | inverse.set_origin_tag(tag); | 953 | 288 | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 288 | return inverse; | 955 | 288 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b Line | Count | Source | 885 | 670 | { | 886 | 670 | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 670 | denominator.reduction_check(); | 891 | 670 | Builder* ctx = denominator.context; | 892 | 670 | uint512_t numerator_values(0); | 893 | 670 | bool numerator_constant = true; | 894 | 670 | OriginTag tag = denominator.get_origin_tag(); | 895 | 685 | for (const auto& numerator_element : numerators) { | 896 | 685 | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 685 | numerator_element.reduction_check(); | 898 | 685 | numerator_values += numerator_element.get_value(); | 899 | 685 | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 685 | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 685 | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 670 | const uint1024_t left = uint1024_t(numerator_values); | 906 | 670 | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 670 | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 670 | uint512_t inverse_value(0); | 910 | 670 | if (right.lo != uint512_t(0)) { | 911 | 670 | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 670 | } | 913 | 670 | uint1024_t inverse_1024(inverse_value); | 914 | 670 | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 670 | const uint1024_t quotient_1024 = | 917 | 670 | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 670 | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 670 | bigfield inverse; | 921 | 670 | bigfield quotient; | 922 | 670 | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 670 | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 670 | std::vector<uint1024_t> numerator_max; | 929 | 685 | for (const auto& n : numerators) { | 930 | 685 | numerator_max.push_back(n.get_maximum_value()); | 931 | 685 | } | 932 | | | 933 | 670 | auto [reduction_required, num_quotient_bits] = | 934 | 670 | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 670 | { denominator.get_maximum_value() }, | 936 | 670 | { unreduced_zero() }, | 937 | 670 | numerator_max); | 938 | 670 | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 670 | if (check_for_zero) { | 945 | 0 | denominator.assert_is_not_equal(zero()); | 946 | 0 | } | 947 | | | 948 | 670 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 670 | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 670 | } | 951 | | | 952 | 670 | inverse.set_origin_tag(tag); | 953 | 670 | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 670 | return inverse; | 955 | 670 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b Line | Count | Source | 885 | 10 | { | 886 | 10 | if (numerators.size() == 0) { | 887 | 0 | return bigfield<Builder, T>(denominator.get_context(), uint256_t(0)); | 888 | 0 | } | 889 | | | 890 | 10 | denominator.reduction_check(); | 891 | 10 | Builder* ctx = denominator.context; | 892 | 10 | uint512_t numerator_values(0); | 893 | 10 | bool numerator_constant = true; | 894 | 10 | OriginTag tag = denominator.get_origin_tag(); | 895 | 10 | for (const auto& numerator_element : numerators) { | 896 | 10 | ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx; | 897 | 10 | numerator_element.reduction_check(); | 898 | 10 | numerator_values += numerator_element.get_value(); | 899 | 10 | numerator_constant = numerator_constant && (numerator_element.is_constant()); | 900 | 10 | tag = OriginTag(tag, numerator_element.get_origin_tag()); | 901 | 10 | } | 902 | | | 903 | | // a / b = c | 904 | | // => c * b = a mod p | 905 | 10 | const uint1024_t left = uint1024_t(numerator_values); | 906 | 10 | const uint1024_t right = uint1024_t(denominator.get_value()); | 907 | 10 | const uint1024_t modulus(target_basis.modulus); | 908 | | // We don't want to trigger the uint assert | 909 | 10 | uint512_t inverse_value(0); | 910 | 10 | if (right.lo != uint512_t(0)) { | 911 | 10 | inverse_value = right.lo.invmod(target_basis.modulus).lo; | 912 | 10 | } | 913 | 10 | uint1024_t inverse_1024(inverse_value); | 914 | 10 | inverse_value = ((left * inverse_1024) % modulus).lo; | 915 | | | 916 | 10 | const uint1024_t quotient_1024 = | 917 | 10 | (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus; | 918 | 10 | const uint512_t quotient_value = quotient_1024.lo; | 919 | | | 920 | 10 | bigfield inverse; | 921 | 10 | bigfield quotient; | 922 | 10 | if (numerator_constant && denominator.is_constant()) { | 923 | 0 | inverse = bigfield(ctx, uint256_t(inverse_value)); | 924 | 0 | inverse.set_origin_tag(tag); | 925 | 0 | return inverse; | 926 | 10 | } else { | 927 | | // We only add the check if the result is non-constant | 928 | 10 | std::vector<uint1024_t> numerator_max; | 929 | 10 | for (const auto& n : numerators) { | 930 | 10 | numerator_max.push_back(n.get_maximum_value()); | 931 | 10 | } | 932 | | | 933 | 10 | auto [reduction_required, num_quotient_bits] = | 934 | 10 | get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) }, | 935 | 10 | { denominator.get_maximum_value() }, | 936 | 10 | { unreduced_zero() }, | 937 | 10 | numerator_max); | 938 | 10 | if (reduction_required) { | 939 | |
| 940 | 0 | denominator.self_reduce(); | 941 | 0 | return internal_div(numerators, denominator, check_for_zero); | 942 | 0 | } | 943 | | // We do this after the quotient check, since this creates gates and we don't want to do this twice | 944 | 10 | if (check_for_zero) { | 945 | 8 | denominator.assert_is_not_equal(zero()); | 946 | 8 | } | 947 | | | 948 | 10 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 949 | 10 | inverse = create_from_u512_as_witness(ctx, inverse_value); | 950 | 10 | } | 951 | | | 952 | 10 | inverse.set_origin_tag(tag); | 953 | 10 | unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators); | 954 | 10 | return inverse; | 955 | 10 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b |
956 | | |
957 | | /** |
958 | | * Div method without constraining denominator!=0. |
959 | | * |
960 | | * Similar to operator/ but numerator can be linear sum of multiple elements |
961 | | * |
962 | | **/ |
963 | | template <typename Builder, typename T> |
964 | | bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const std::vector<bigfield>& numerators, |
965 | | const bigfield& denominator) |
966 | 113k | { |
967 | 113k | return internal_div(numerators, denominator, false); |
968 | 113k | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_ Line | Count | Source | 966 | 101k | { | 967 | 101k | return internal_div(numerators, denominator, false); | 968 | 101k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS8_SaIS8_EERKS8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_ Line | Count | Source | 966 | 488 | { | 967 | 488 | return internal_div(numerators, denominator, false); | 968 | 488 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_ _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_ Line | Count | Source | 966 | 10.9k | { | 967 | 10.9k | return internal_div(numerators, denominator, false); | 968 | 10.9k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_ Line | Count | Source | 966 | 670 | { | 967 | 670 | return internal_div(numerators, denominator, false); | 968 | 670 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_ |
969 | | |
970 | | template <typename Builder, typename T> |
971 | | bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const bigfield& denominator) |
972 | 292 | { |
973 | 292 | return internal_div({ *this }, denominator, false); |
974 | 292 | } Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS7_ Line | Count | Source | 972 | 2 | { | 973 | 2 | return internal_div({ *this }, denominator, false); | 974 | 2 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS9_ _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS9_ Line | Count | Source | 972 | 288 | { | 973 | 288 | return internal_div({ *this }, denominator, false); | 974 | 288 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS7_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS7_ Line | Count | Source | 972 | 2 | { | 973 | 2 | return internal_div({ *this }, denominator, false); | 974 | 2 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS9_ |
975 | | |
976 | | /** |
977 | | * Div method with constraints for denominator!=0. |
978 | | * |
979 | | * Similar to operator/ but numerator can be linear sum of multiple elements |
980 | | * |
981 | | * TODO: After we create a mechanism for easy updating of witnesses, create a test with proof check |
982 | | **/ |
983 | | template <typename Builder, typename T> |
984 | | bigfield<Builder, T> bigfield<Builder, T>::div_check_denominator_nonzero(const std::vector<bigfield>& numerators, |
985 | | const bigfield& denominator) |
986 | 1 | { |
987 | 1 | return internal_div(numerators, denominator, true); |
988 | 1 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_ Line | Count | Source | 986 | 1 | { | 987 | 1 | return internal_div(numerators, denominator, true); | 988 | 1 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS8_SaIS8_EERKS8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_ |
989 | | /** |
990 | | * Compute a * a = c mod p |
991 | | * |
992 | | * Slightly cheaper than operator* for Standard |
993 | | **/ |
994 | | template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::sqr() const |
995 | 3.50k | { |
996 | 3.50k | reduction_check(); |
997 | 3.50k | Builder* ctx = context; |
998 | | |
999 | 3.50k | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {}); |
1000 | | |
1001 | 3.50k | bigfield remainder; |
1002 | 3.50k | bigfield quotient; |
1003 | 3.50k | if (is_constant()) { |
1004 | 208 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); |
1005 | 208 | return remainder; |
1006 | 3.29k | } else { |
1007 | | |
1008 | 3.29k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( |
1009 | 3.29k | { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER }); |
1010 | 3.29k | if (reduction_required) { |
1011 | 1 | self_reduce(); |
1012 | 1 | return sqr(); |
1013 | 1 | } |
1014 | | |
1015 | 3.29k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
1016 | 3.29k | remainder = create_from_u512_as_witness(ctx, remainder_value); |
1017 | 3.29k | }; |
1018 | | |
1019 | 3.29k | unsafe_evaluate_square_add(*this, {}, quotient, remainder); |
1020 | 3.29k | remainder.set_origin_tag(get_origin_tag()); |
1021 | 3.29k | return remainder; |
1022 | 3.50k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sqrEv Line | Count | Source | 995 | 3.20k | { | 996 | 3.20k | reduction_check(); | 997 | 3.20k | Builder* ctx = context; | 998 | | | 999 | 3.20k | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {}); | 1000 | | | 1001 | 3.20k | bigfield remainder; | 1002 | 3.20k | bigfield quotient; | 1003 | 3.20k | if (is_constant()) { | 1004 | 208 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1005 | 208 | return remainder; | 1006 | 2.99k | } else { | 1007 | | | 1008 | 2.99k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1009 | 2.99k | { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER }); | 1010 | 2.99k | if (reduction_required) { | 1011 | 1 | self_reduce(); | 1012 | 1 | return sqr(); | 1013 | 1 | } | 1014 | | | 1015 | 2.99k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1016 | 2.99k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1017 | 2.99k | }; | 1018 | | | 1019 | 2.99k | unsafe_evaluate_square_add(*this, {}, quotient, remainder); | 1020 | 2.99k | remainder.set_origin_tag(get_origin_tag()); | 1021 | 2.99k | return remainder; | 1022 | 3.20k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sqrEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sqrEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sqrEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sqrEv Line | Count | Source | 995 | 9 | { | 996 | 9 | reduction_check(); | 997 | 9 | Builder* ctx = context; | 998 | | | 999 | 9 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {}); | 1000 | | | 1001 | 9 | bigfield remainder; | 1002 | 9 | bigfield quotient; | 1003 | 9 | if (is_constant()) { | 1004 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1005 | 0 | return remainder; | 1006 | 9 | } else { | 1007 | | | 1008 | 9 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1009 | 9 | { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER }); | 1010 | 9 | if (reduction_required) { | 1011 | 0 | self_reduce(); | 1012 | 0 | return sqr(); | 1013 | 0 | } | 1014 | | | 1015 | 9 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1016 | 9 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1017 | 9 | }; | 1018 | | | 1019 | 9 | unsafe_evaluate_square_add(*this, {}, quotient, remainder); | 1020 | 9 | remainder.set_origin_tag(get_origin_tag()); | 1021 | 9 | return remainder; | 1022 | 9 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sqrEv _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sqrEv Line | Count | Source | 995 | 288 | { | 996 | 288 | reduction_check(); | 997 | 288 | Builder* ctx = context; | 998 | | | 999 | 288 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {}); | 1000 | | | 1001 | 288 | bigfield remainder; | 1002 | 288 | bigfield quotient; | 1003 | 288 | if (is_constant()) { | 1004 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1005 | 0 | return remainder; | 1006 | 288 | } else { | 1007 | | | 1008 | 288 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1009 | 288 | { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER }); | 1010 | 288 | if (reduction_required) { | 1011 | 0 | self_reduce(); | 1012 | 0 | return sqr(); | 1013 | 0 | } | 1014 | | | 1015 | 288 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1016 | 288 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1017 | 288 | }; | 1018 | | | 1019 | 288 | unsafe_evaluate_square_add(*this, {}, quotient, remainder); | 1020 | 288 | remainder.set_origin_tag(get_origin_tag()); | 1021 | 288 | return remainder; | 1022 | 288 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sqrEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sqrEv Line | Count | Source | 995 | 6 | { | 996 | 6 | reduction_check(); | 997 | 6 | Builder* ctx = context; | 998 | | | 999 | 6 | const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {}); | 1000 | | | 1001 | 6 | bigfield remainder; | 1002 | 6 | bigfield quotient; | 1003 | 6 | if (is_constant()) { | 1004 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1005 | 0 | return remainder; | 1006 | 6 | } else { | 1007 | | | 1008 | 6 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1009 | 6 | { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER }); | 1010 | 6 | if (reduction_required) { | 1011 | 0 | self_reduce(); | 1012 | 0 | return sqr(); | 1013 | 0 | } | 1014 | | | 1015 | 6 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1016 | 6 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1017 | 6 | }; | 1018 | | | 1019 | 6 | unsafe_evaluate_square_add(*this, {}, quotient, remainder); | 1020 | 6 | remainder.set_origin_tag(get_origin_tag()); | 1021 | 6 | return remainder; | 1022 | 6 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sqrEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sqrEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sqrEv |
1023 | | |
1024 | | /** |
1025 | | * Compute a * a + ...to_add = b mod p |
1026 | | * |
1027 | | * We can chain multiple additions to a square/multiply with a single quotient/remainder. |
1028 | | * |
1029 | | * Chaining the additions here is cheaper than calling operator+ because we can combine some gates in |
1030 | | *`evaluate_multiply_add` |
1031 | | **/ |
1032 | | template <typename Builder, typename T> |
1033 | | bigfield<Builder, T> bigfield<Builder, T>::sqradd(const std::vector<bigfield>& to_add) const |
1034 | 377k | { |
1035 | 377k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
1036 | 0 | reduction_check(); |
1037 | |
|
1038 | 0 | Builder* ctx = context; |
1039 | |
|
1040 | 0 | uint512_t add_values(0); |
1041 | 0 | bool add_constant = true; |
1042 | 723k | for (const auto& add_element : to_add) { |
1043 | 723k | add_element.reduction_check(); |
1044 | 723k | add_values += add_element.get_value(); |
1045 | 723k | add_constant = add_constant && (add_element.is_constant()); |
1046 | 723k | } |
1047 | |
|
1048 | 0 | const uint1024_t left(get_value()); |
1049 | 0 | const uint1024_t right(get_value()); |
1050 | 0 | const uint1024_t add_right(add_values); |
1051 | 0 | const uint1024_t modulus(target_basis.modulus); |
1052 | |
|
1053 | 0 | bigfield remainder; |
1054 | 0 | bigfield quotient; |
1055 | 377k | if (is_constant()) { |
1056 | 2 | if (add_constant) { |
1057 | | |
1058 | 2 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); |
1059 | 2 | remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); |
1060 | | // Merge tags |
1061 | 2 | OriginTag new_tag = get_origin_tag(); |
1062 | 2 | for (auto& element : to_add) { |
1063 | 2 | new_tag = OriginTag(new_tag, element.get_origin_tag()); |
1064 | 2 | } |
1065 | 2 | remainder.set_origin_tag(new_tag); |
1066 | 2 | return remainder; |
1067 | 2 | } else { |
1068 | |
|
1069 | 0 | const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus); |
1070 | 0 | std::vector<bigfield> new_to_add; |
1071 | 0 | for (auto& add_element : to_add) { |
1072 | 0 | new_to_add.push_back(add_element); |
1073 | 0 | } |
1074 | |
|
1075 | 0 | new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo)); |
1076 | 0 | return sum(new_to_add); |
1077 | 0 | } |
1078 | 377k | } else { |
1079 | | |
1080 | | // Check the quotient fits the range proof |
1081 | 377k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( |
1082 | 377k | { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); |
1083 | | |
1084 | 377k | if (reduction_required) { |
1085 | 1 | self_reduce(); |
1086 | 1 | return sqradd(to_add); |
1087 | 1 | } |
1088 | 377k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); |
1089 | 377k | uint512_t quotient_value = quotient_1024.lo; |
1090 | 377k | uint256_t remainder_value = remainder_1024.lo.lo; |
1091 | | |
1092 | 377k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
1093 | 377k | remainder = create_from_u512_as_witness(ctx, remainder_value); |
1094 | 377k | }; |
1095 | 377k | OriginTag new_tag = get_origin_tag(); |
1096 | 723k | for (auto& element : to_add) { |
1097 | 723k | new_tag = OriginTag(new_tag, element.get_origin_tag()); |
1098 | 723k | } |
1099 | 377k | remainder.set_origin_tag(new_tag); |
1100 | 377k | unsafe_evaluate_square_add(*this, to_add, quotient, remainder); |
1101 | 377k | return remainder; |
1102 | 0 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE Line | Count | Source | 1034 | 354k | { | 1035 | 354k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1036 | 354k | reduction_check(); | 1037 | | | 1038 | 354k | Builder* ctx = context; | 1039 | | | 1040 | 354k | uint512_t add_values(0); | 1041 | 354k | bool add_constant = true; | 1042 | 682k | for (const auto& add_element : to_add) { | 1043 | 682k | add_element.reduction_check(); | 1044 | 682k | add_values += add_element.get_value(); | 1045 | 682k | add_constant = add_constant && (add_element.is_constant()); | 1046 | 682k | } | 1047 | | | 1048 | 354k | const uint1024_t left(get_value()); | 1049 | 354k | const uint1024_t right(get_value()); | 1050 | 354k | const uint1024_t add_right(add_values); | 1051 | 354k | const uint1024_t modulus(target_basis.modulus); | 1052 | | | 1053 | 354k | bigfield remainder; | 1054 | 354k | bigfield quotient; | 1055 | 354k | if (is_constant()) { | 1056 | 2 | if (add_constant) { | 1057 | | | 1058 | 2 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1059 | 2 | remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1060 | | // Merge tags | 1061 | 2 | OriginTag new_tag = get_origin_tag(); | 1062 | 2 | for (auto& element : to_add) { | 1063 | 2 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1064 | 2 | } | 1065 | 2 | remainder.set_origin_tag(new_tag); | 1066 | 2 | return remainder; | 1067 | 2 | } else { | 1068 | |
| 1069 | 0 | const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus); | 1070 | 0 | std::vector<bigfield> new_to_add; | 1071 | 0 | for (auto& add_element : to_add) { | 1072 | 0 | new_to_add.push_back(add_element); | 1073 | 0 | } | 1074 | |
| 1075 | 0 | new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo)); | 1076 | 0 | return sum(new_to_add); | 1077 | 0 | } | 1078 | 354k | } else { | 1079 | | | 1080 | | // Check the quotient fits the range proof | 1081 | 354k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1082 | 354k | { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1083 | | | 1084 | 354k | if (reduction_required) { | 1085 | 1 | self_reduce(); | 1086 | 1 | return sqradd(to_add); | 1087 | 1 | } | 1088 | 354k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1089 | 354k | uint512_t quotient_value = quotient_1024.lo; | 1090 | 354k | uint256_t remainder_value = remainder_1024.lo.lo; | 1091 | | | 1092 | 354k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1093 | 354k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1094 | 354k | }; | 1095 | 354k | OriginTag new_tag = get_origin_tag(); | 1096 | 682k | for (auto& element : to_add) { | 1097 | 682k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1098 | 682k | } | 1099 | 354k | remainder.set_origin_tag(new_tag); | 1100 | 354k | unsafe_evaluate_square_add(*this, to_add, quotient, remainder); | 1101 | 354k | return remainder; | 1102 | 354k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE Line | Count | Source | 1034 | 1.00k | { | 1035 | 1.00k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1036 | 1.00k | reduction_check(); | 1037 | | | 1038 | 1.00k | Builder* ctx = context; | 1039 | | | 1040 | 1.00k | uint512_t add_values(0); | 1041 | 1.00k | bool add_constant = true; | 1042 | 1.69k | for (const auto& add_element : to_add) { | 1043 | 1.69k | add_element.reduction_check(); | 1044 | 1.69k | add_values += add_element.get_value(); | 1045 | 1.69k | add_constant = add_constant && (add_element.is_constant()); | 1046 | 1.69k | } | 1047 | | | 1048 | 1.00k | const uint1024_t left(get_value()); | 1049 | 1.00k | const uint1024_t right(get_value()); | 1050 | 1.00k | const uint1024_t add_right(add_values); | 1051 | 1.00k | const uint1024_t modulus(target_basis.modulus); | 1052 | | | 1053 | 1.00k | bigfield remainder; | 1054 | 1.00k | bigfield quotient; | 1055 | 1.00k | if (is_constant()) { | 1056 | 0 | if (add_constant) { | 1057 | |
| 1058 | 0 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1059 | 0 | remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1060 | | // Merge tags | 1061 | 0 | OriginTag new_tag = get_origin_tag(); | 1062 | 0 | for (auto& element : to_add) { | 1063 | 0 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1064 | 0 | } | 1065 | 0 | remainder.set_origin_tag(new_tag); | 1066 | 0 | return remainder; | 1067 | 0 | } else { | 1068 | |
| 1069 | 0 | const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus); | 1070 | 0 | std::vector<bigfield> new_to_add; | 1071 | 0 | for (auto& add_element : to_add) { | 1072 | 0 | new_to_add.push_back(add_element); | 1073 | 0 | } | 1074 | |
| 1075 | 0 | new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo)); | 1076 | 0 | return sum(new_to_add); | 1077 | 0 | } | 1078 | 1.00k | } else { | 1079 | | | 1080 | | // Check the quotient fits the range proof | 1081 | 1.00k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1082 | 1.00k | { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1083 | | | 1084 | 1.00k | if (reduction_required) { | 1085 | 0 | self_reduce(); | 1086 | 0 | return sqradd(to_add); | 1087 | 0 | } | 1088 | 1.00k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1089 | 1.00k | uint512_t quotient_value = quotient_1024.lo; | 1090 | 1.00k | uint256_t remainder_value = remainder_1024.lo.lo; | 1091 | | | 1092 | 1.00k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1093 | 1.00k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1094 | 1.00k | }; | 1095 | 1.00k | OriginTag new_tag = get_origin_tag(); | 1096 | 1.69k | for (auto& element : to_add) { | 1097 | 1.69k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1098 | 1.69k | } | 1099 | 1.00k | remainder.set_origin_tag(new_tag); | 1100 | 1.00k | unsafe_evaluate_square_add(*this, to_add, quotient, remainder); | 1101 | 1.00k | return remainder; | 1102 | 1.00k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE Line | Count | Source | 1034 | 20.5k | { | 1035 | 20.5k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1036 | 20.5k | reduction_check(); | 1037 | | | 1038 | 20.5k | Builder* ctx = context; | 1039 | | | 1040 | 20.5k | uint512_t add_values(0); | 1041 | 20.5k | bool add_constant = true; | 1042 | 36.4k | for (const auto& add_element : to_add) { | 1043 | 36.4k | add_element.reduction_check(); | 1044 | 36.4k | add_values += add_element.get_value(); | 1045 | 36.4k | add_constant = add_constant && (add_element.is_constant()); | 1046 | 36.4k | } | 1047 | | | 1048 | 20.5k | const uint1024_t left(get_value()); | 1049 | 20.5k | const uint1024_t right(get_value()); | 1050 | 20.5k | const uint1024_t add_right(add_values); | 1051 | 20.5k | const uint1024_t modulus(target_basis.modulus); | 1052 | | | 1053 | 20.5k | bigfield remainder; | 1054 | 20.5k | bigfield quotient; | 1055 | 20.5k | if (is_constant()) { | 1056 | 0 | if (add_constant) { | 1057 | |
| 1058 | 0 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1059 | 0 | remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1060 | | // Merge tags | 1061 | 0 | OriginTag new_tag = get_origin_tag(); | 1062 | 0 | for (auto& element : to_add) { | 1063 | 0 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1064 | 0 | } | 1065 | 0 | remainder.set_origin_tag(new_tag); | 1066 | 0 | return remainder; | 1067 | 0 | } else { | 1068 | |
| 1069 | 0 | const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus); | 1070 | 0 | std::vector<bigfield> new_to_add; | 1071 | 0 | for (auto& add_element : to_add) { | 1072 | 0 | new_to_add.push_back(add_element); | 1073 | 0 | } | 1074 | |
| 1075 | 0 | new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo)); | 1076 | 0 | return sum(new_to_add); | 1077 | 0 | } | 1078 | 20.5k | } else { | 1079 | | | 1080 | | // Check the quotient fits the range proof | 1081 | 20.5k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1082 | 20.5k | { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1083 | | | 1084 | 20.5k | if (reduction_required) { | 1085 | 0 | self_reduce(); | 1086 | 0 | return sqradd(to_add); | 1087 | 0 | } | 1088 | 20.5k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1089 | 20.5k | uint512_t quotient_value = quotient_1024.lo; | 1090 | 20.5k | uint256_t remainder_value = remainder_1024.lo.lo; | 1091 | | | 1092 | 20.5k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1093 | 20.5k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1094 | 20.5k | }; | 1095 | 20.5k | OriginTag new_tag = get_origin_tag(); | 1096 | 36.4k | for (auto& element : to_add) { | 1097 | 36.4k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1098 | 36.4k | } | 1099 | 20.5k | remainder.set_origin_tag(new_tag); | 1100 | 20.5k | unsafe_evaluate_square_add(*this, to_add, quotient, remainder); | 1101 | 20.5k | return remainder; | 1102 | 20.5k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE Line | Count | Source | 1034 | 1.30k | { | 1035 | 1.30k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1036 | 1.30k | reduction_check(); | 1037 | | | 1038 | 1.30k | Builder* ctx = context; | 1039 | | | 1040 | 1.30k | uint512_t add_values(0); | 1041 | 1.30k | bool add_constant = true; | 1042 | 2.60k | for (const auto& add_element : to_add) { | 1043 | 2.60k | add_element.reduction_check(); | 1044 | 2.60k | add_values += add_element.get_value(); | 1045 | 2.60k | add_constant = add_constant && (add_element.is_constant()); | 1046 | 2.60k | } | 1047 | | | 1048 | 1.30k | const uint1024_t left(get_value()); | 1049 | 1.30k | const uint1024_t right(get_value()); | 1050 | 1.30k | const uint1024_t add_right(add_values); | 1051 | 1.30k | const uint1024_t modulus(target_basis.modulus); | 1052 | | | 1053 | 1.30k | bigfield remainder; | 1054 | 1.30k | bigfield quotient; | 1055 | 1.30k | if (is_constant()) { | 1056 | 0 | if (add_constant) { | 1057 | |
| 1058 | 0 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1059 | 0 | remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1060 | | // Merge tags | 1061 | 0 | OriginTag new_tag = get_origin_tag(); | 1062 | 0 | for (auto& element : to_add) { | 1063 | 0 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1064 | 0 | } | 1065 | 0 | remainder.set_origin_tag(new_tag); | 1066 | 0 | return remainder; | 1067 | 0 | } else { | 1068 | |
| 1069 | 0 | const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus); | 1070 | 0 | std::vector<bigfield> new_to_add; | 1071 | 0 | for (auto& add_element : to_add) { | 1072 | 0 | new_to_add.push_back(add_element); | 1073 | 0 | } | 1074 | |
| 1075 | 0 | new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo)); | 1076 | 0 | return sum(new_to_add); | 1077 | 0 | } | 1078 | 1.30k | } else { | 1079 | | | 1080 | | // Check the quotient fits the range proof | 1081 | 1.30k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1082 | 1.30k | { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1083 | | | 1084 | 1.30k | if (reduction_required) { | 1085 | 0 | self_reduce(); | 1086 | 0 | return sqradd(to_add); | 1087 | 0 | } | 1088 | 1.30k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 1089 | 1.30k | uint512_t quotient_value = quotient_1024.lo; | 1090 | 1.30k | uint256_t remainder_value = remainder_1024.lo.lo; | 1091 | | | 1092 | 1.30k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1093 | 1.30k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1094 | 1.30k | }; | 1095 | 1.30k | OriginTag new_tag = get_origin_tag(); | 1096 | 2.60k | for (auto& element : to_add) { | 1097 | 2.60k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1098 | 2.60k | } | 1099 | 1.30k | remainder.set_origin_tag(new_tag); | 1100 | 1.30k | unsafe_evaluate_square_add(*this, to_add, quotient, remainder); | 1101 | 1.30k | return remainder; | 1102 | 1.30k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE |
1103 | | |
1104 | | /** |
1105 | | * @brief Raise a bigfield to a power of an exponent. Note that the exponent must not exceed 32 bits and is |
1106 | | * implicitly range constrained. |
1107 | | * |
1108 | | * @returns this ** (exponent) |
1109 | | * |
1110 | | * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function. |
1111 | | */ |
1112 | | |
1113 | | template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::pow(const size_t exponent) const |
1114 | 56 | { |
1115 | | // Just return one immediately |
1116 | | |
1117 | 56 | if (exponent == 0) { |
1118 | 0 | return bigfield(uint256_t(1)); |
1119 | 0 | } |
1120 | | |
1121 | 56 | bool accumulator_initialized = false; |
1122 | 56 | bigfield accumulator; |
1123 | 56 | bigfield running_power = *this; |
1124 | 56 | auto shifted_exponent = exponent; |
1125 | | |
1126 | | // Square and multiply |
1127 | 662 | while (shifted_exponent != 0) { |
1128 | 606 | if (shifted_exponent & 1) { |
1129 | 378 | if (!accumulator_initialized) { |
1130 | 56 | accumulator = running_power; |
1131 | 56 | accumulator_initialized = true; |
1132 | 322 | } else { |
1133 | 322 | accumulator *= running_power; |
1134 | 322 | } |
1135 | 378 | } |
1136 | 606 | if (shifted_exponent != 0) { |
1137 | 606 | running_power = running_power.sqr(); |
1138 | 606 | } |
1139 | 606 | shifted_exponent >>= 1; |
1140 | 606 | } |
1141 | 56 | return accumulator; |
1142 | 56 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powEm Line | Count | Source | 1114 | 56 | { | 1115 | | // Just return one immediately | 1116 | | | 1117 | 56 | if (exponent == 0) { | 1118 | 0 | return bigfield(uint256_t(1)); | 1119 | 0 | } | 1120 | | | 1121 | 56 | bool accumulator_initialized = false; | 1122 | 56 | bigfield accumulator; | 1123 | 56 | bigfield running_power = *this; | 1124 | 56 | auto shifted_exponent = exponent; | 1125 | | | 1126 | | // Square and multiply | 1127 | 662 | while (shifted_exponent != 0) { | 1128 | 606 | if (shifted_exponent & 1) { | 1129 | 378 | if (!accumulator_initialized) { | 1130 | 56 | accumulator = running_power; | 1131 | 56 | accumulator_initialized = true; | 1132 | 322 | } else { | 1133 | 322 | accumulator *= running_power; | 1134 | 322 | } | 1135 | 378 | } | 1136 | 606 | if (shifted_exponent != 0) { | 1137 | 606 | running_power = running_power.sqr(); | 1138 | 606 | } | 1139 | 606 | shifted_exponent >>= 1; | 1140 | 606 | } | 1141 | 56 | return accumulator; | 1142 | 56 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powEm Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powEm |
1143 | | |
1144 | | /** |
1145 | | * @brief Raise a bigfield to a power of an exponent (field_t) that must be a witness. Note that the exponent must |
1146 | | * not exceed 32 bits and is implicitly range constrained. |
1147 | | * |
1148 | | * @returns this ** (exponent) |
1149 | | * |
1150 | | * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function. |
1151 | | */ |
1152 | | template <typename Builder, typename T> |
1153 | | bigfield<Builder, T> bigfield<Builder, T>::pow(const field_t<Builder>& exponent) const |
1154 | 20 | { |
1155 | 20 | auto* ctx = get_context() ? get_context() : exponent.get_context(); |
1156 | 20 | uint256_t exponent_value = exponent.get_value(); |
1157 | | |
1158 | 20 | ASSERT(exponent_value.get_msb() < 32); |
1159 | | // Use the constant version that perfoms only the necessary multiplications if the exponent is constant |
1160 | 20 | if (exponent.is_constant()) { |
1161 | 0 | return this->pow(static_cast<uint32_t>(exponent_value)); |
1162 | 0 | } |
1163 | 20 | std::vector<bool_t<Builder>> exponent_bits(32); |
1164 | | // Collect individual bits as bool_t's |
1165 | 660 | for (size_t i = 0; i < exponent_bits.size(); ++i) { |
1166 | 640 | uint256_t value_bit = exponent_value & 1; |
1167 | 640 | bool_t<Builder> bit; |
1168 | 640 | bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0])); |
1169 | 640 | exponent_bits[31 - i] = (bit); |
1170 | 640 | exponent_value >>= 1; |
1171 | 640 | } |
1172 | | |
1173 | 20 | field_t<Builder> exponent_accumulator(ctx, 0); |
1174 | | |
1175 | | // Reconstruct the exponent from bits |
1176 | 640 | for (const auto& bit : exponent_bits) { |
1177 | 640 | exponent_accumulator += exponent_accumulator; |
1178 | 640 | exponent_accumulator += field_t<Builder>(bit); |
1179 | 640 | } |
1180 | | |
1181 | | // Ensure it's equal to the original |
1182 | 20 | exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect"); |
1183 | 20 | bigfield accumulator(ctx, 1); |
1184 | 20 | bigfield one(1); |
1185 | | // Compute the power with a square-and-multiply algorithm |
1186 | 660 | for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) { |
1187 | 640 | accumulator *= accumulator; |
1188 | 640 | accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]); |
1189 | 640 | } |
1190 | 20 | accumulator.self_reduce(); |
1191 | 20 | accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag)); |
1192 | 20 | return accumulator; |
1193 | 0 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE Line | Count | Source | 1154 | 20 | { | 1155 | 20 | auto* ctx = get_context() ? get_context() : exponent.get_context(); | 1156 | 20 | uint256_t exponent_value = exponent.get_value(); | 1157 | | | 1158 | 20 | ASSERT(exponent_value.get_msb() < 32); | 1159 | | // Use the constant version that perfoms only the necessary multiplications if the exponent is constant | 1160 | 20 | if (exponent.is_constant()) { | 1161 | 0 | return this->pow(static_cast<uint32_t>(exponent_value)); | 1162 | 0 | } | 1163 | 20 | std::vector<bool_t<Builder>> exponent_bits(32); | 1164 | | // Collect individual bits as bool_t's | 1165 | 660 | for (size_t i = 0; i < exponent_bits.size(); ++i) { | 1166 | 640 | uint256_t value_bit = exponent_value & 1; | 1167 | 640 | bool_t<Builder> bit; | 1168 | 640 | bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0])); | 1169 | 640 | exponent_bits[31 - i] = (bit); | 1170 | 640 | exponent_value >>= 1; | 1171 | 640 | } | 1172 | | | 1173 | 20 | field_t<Builder> exponent_accumulator(ctx, 0); | 1174 | | | 1175 | | // Reconstruct the exponent from bits | 1176 | 640 | for (const auto& bit : exponent_bits) { | 1177 | 640 | exponent_accumulator += exponent_accumulator; | 1178 | 640 | exponent_accumulator += field_t<Builder>(bit); | 1179 | 640 | } | 1180 | | | 1181 | | // Ensure it's equal to the original | 1182 | 20 | exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect"); | 1183 | 20 | bigfield accumulator(ctx, 1); | 1184 | 20 | bigfield one(1); | 1185 | | // Compute the power with a square-and-multiply algorithm | 1186 | 660 | for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) { | 1187 | 640 | accumulator *= accumulator; | 1188 | 640 | accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]); | 1189 | 640 | } | 1190 | 20 | accumulator.self_reduce(); | 1191 | 20 | accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag)); | 1192 | 20 | return accumulator; | 1193 | 20 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE |
1194 | | |
1195 | | /** |
1196 | | * Compute a * b + ...to_add = c mod p |
1197 | | * |
1198 | | * @param to_mul Bigfield element to multiply by |
1199 | | * @param to_add Vector of elements to add |
1200 | | * |
1201 | | * @return New bigfield elment c |
1202 | | **/ |
1203 | | template <typename Builder, typename T> |
1204 | | bigfield<Builder, T> bigfield<Builder, T>::madd(const bigfield& to_mul, const std::vector<bigfield>& to_add) const |
1205 | 121k | { |
1206 | 121k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
1207 | 121k | Builder* ctx = context ? context : to_mul.context; |
1208 | 0 | reduction_check(); |
1209 | 0 | to_mul.reduction_check(); |
1210 | |
|
1211 | 0 | uint512_t add_values(0); |
1212 | 0 | bool add_constant = true; |
1213 | |
|
1214 | 197k | for (const auto& add_element : to_add) { |
1215 | 197k | add_element.reduction_check(); |
1216 | 197k | add_values += add_element.get_value(); |
1217 | 197k | add_constant = add_constant && (add_element.is_constant()); |
1218 | 197k | } |
1219 | |
|
1220 | 0 | const uint1024_t left(get_value()); |
1221 | 0 | const uint1024_t mul_right(to_mul.get_value()); |
1222 | 0 | const uint1024_t add_right(add_values); |
1223 | 0 | const uint1024_t modulus(target_basis.modulus); |
1224 | |
|
1225 | 0 | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); |
1226 | |
|
1227 | 0 | const uint512_t quotient_value = quotient_1024.lo; |
1228 | 0 | const uint512_t remainder_value = remainder_1024.lo; |
1229 | |
|
1230 | 0 | bigfield remainder; |
1231 | 0 | bigfield quotient; |
1232 | 121k | if (is_constant() && to_mul.is_constant() && add_constant) { |
1233 | 2 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); |
1234 | 2 | return remainder; |
1235 | 121k | } else { |
1236 | | |
1237 | 121k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( |
1238 | 121k | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); |
1239 | 121k | if (reduction_required) { |
1240 | 1 | if (get_maximum_value() > to_mul.get_maximum_value()) { |
1241 | 0 | self_reduce(); |
1242 | 1 | } else { |
1243 | 1 | to_mul.self_reduce(); |
1244 | 1 | } |
1245 | 1 | return (*this).madd(to_mul, to_add); |
1246 | 1 | } |
1247 | 121k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
1248 | 121k | remainder = create_from_u512_as_witness(ctx, remainder_value); |
1249 | 121k | }; |
1250 | 121k | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); |
1251 | 121k | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); |
1252 | 197k | for (auto& element : to_add) { |
1253 | 197k | new_tag = OriginTag(new_tag, element.get_origin_tag()); |
1254 | 197k | } |
1255 | 121k | return remainder; |
1256 | 0 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE Line | Count | Source | 1205 | 98.8k | { | 1206 | 98.8k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 98.8k | Builder* ctx = context ? context : to_mul.context; | 1208 | 98.8k | reduction_check(); | 1209 | 98.8k | to_mul.reduction_check(); | 1210 | | | 1211 | 98.8k | uint512_t add_values(0); | 1212 | 98.8k | bool add_constant = true; | 1213 | | | 1214 | 158k | for (const auto& add_element : to_add) { | 1215 | 158k | add_element.reduction_check(); | 1216 | 158k | add_values += add_element.get_value(); | 1217 | 158k | add_constant = add_constant && (add_element.is_constant()); | 1218 | 158k | } | 1219 | | | 1220 | 98.8k | const uint1024_t left(get_value()); | 1221 | 98.8k | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 98.8k | const uint1024_t add_right(add_values); | 1223 | 98.8k | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 98.8k | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 98.8k | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 98.8k | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 98.8k | bigfield remainder; | 1231 | 98.8k | bigfield quotient; | 1232 | 98.8k | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 2 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 2 | return remainder; | 1235 | 98.8k | } else { | 1236 | | | 1237 | 98.8k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 98.8k | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 98.8k | if (reduction_required) { | 1240 | 1 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 1 | } else { | 1243 | 1 | to_mul.self_reduce(); | 1244 | 1 | } | 1245 | 1 | return (*this).madd(to_mul, to_add); | 1246 | 1 | } | 1247 | 98.8k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 98.8k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 98.8k | }; | 1250 | 98.8k | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 98.8k | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 158k | for (auto& element : to_add) { | 1253 | 158k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 158k | } | 1255 | 98.8k | return remainder; | 1256 | 98.8k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 1205 | 974 | { | 1206 | 974 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 974 | Builder* ctx = context ? context : to_mul.context; | 1208 | 974 | reduction_check(); | 1209 | 974 | to_mul.reduction_check(); | 1210 | | | 1211 | 974 | uint512_t add_values(0); | 1212 | 974 | bool add_constant = true; | 1213 | | | 1214 | 1.55k | for (const auto& add_element : to_add) { | 1215 | 1.55k | add_element.reduction_check(); | 1216 | 1.55k | add_values += add_element.get_value(); | 1217 | 1.55k | add_constant = add_constant && (add_element.is_constant()); | 1218 | 1.55k | } | 1219 | | | 1220 | 974 | const uint1024_t left(get_value()); | 1221 | 974 | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 974 | const uint1024_t add_right(add_values); | 1223 | 974 | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 974 | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 974 | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 974 | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 974 | bigfield remainder; | 1231 | 974 | bigfield quotient; | 1232 | 974 | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 0 | return remainder; | 1235 | 974 | } else { | 1236 | | | 1237 | 974 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 974 | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 974 | if (reduction_required) { | 1240 | 0 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 0 | } else { | 1243 | 0 | to_mul.self_reduce(); | 1244 | 0 | } | 1245 | 0 | return (*this).madd(to_mul, to_add); | 1246 | 0 | } | 1247 | 974 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 974 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 974 | }; | 1250 | 974 | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 974 | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 1.55k | for (auto& element : to_add) { | 1253 | 1.55k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 1.55k | } | 1255 | 974 | return remainder; | 1256 | 974 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 1205 | 12 | { | 1206 | 12 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 12 | Builder* ctx = context ? context : to_mul.context; | 1208 | 12 | reduction_check(); | 1209 | 12 | to_mul.reduction_check(); | 1210 | | | 1211 | 12 | uint512_t add_values(0); | 1212 | 12 | bool add_constant = true; | 1213 | | | 1214 | 12 | for (const auto& add_element : to_add) { | 1215 | 12 | add_element.reduction_check(); | 1216 | 12 | add_values += add_element.get_value(); | 1217 | 12 | add_constant = add_constant && (add_element.is_constant()); | 1218 | 12 | } | 1219 | | | 1220 | 12 | const uint1024_t left(get_value()); | 1221 | 12 | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 12 | const uint1024_t add_right(add_values); | 1223 | 12 | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 12 | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 12 | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 12 | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 12 | bigfield remainder; | 1231 | 12 | bigfield quotient; | 1232 | 12 | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 0 | return remainder; | 1235 | 12 | } else { | 1236 | | | 1237 | 12 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 12 | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 12 | if (reduction_required) { | 1240 | 0 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 0 | } else { | 1243 | 0 | to_mul.self_reduce(); | 1244 | 0 | } | 1245 | 0 | return (*this).madd(to_mul, to_add); | 1246 | 0 | } | 1247 | 12 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 12 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 12 | }; | 1250 | 12 | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 12 | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 12 | for (auto& element : to_add) { | 1253 | 12 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 12 | } | 1255 | 12 | return remainder; | 1256 | 12 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE Line | Count | Source | 1205 | 20.3k | { | 1206 | 20.3k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 20.3k | Builder* ctx = context ? context : to_mul.context; | 1208 | 20.3k | reduction_check(); | 1209 | 20.3k | to_mul.reduction_check(); | 1210 | | | 1211 | 20.3k | uint512_t add_values(0); | 1212 | 20.3k | bool add_constant = true; | 1213 | | | 1214 | 34.1k | for (const auto& add_element : to_add) { | 1215 | 34.1k | add_element.reduction_check(); | 1216 | 34.1k | add_values += add_element.get_value(); | 1217 | 34.1k | add_constant = add_constant && (add_element.is_constant()); | 1218 | 34.1k | } | 1219 | | | 1220 | 20.3k | const uint1024_t left(get_value()); | 1221 | 20.3k | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 20.3k | const uint1024_t add_right(add_values); | 1223 | 20.3k | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 20.3k | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 20.3k | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 20.3k | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 20.3k | bigfield remainder; | 1231 | 20.3k | bigfield quotient; | 1232 | 20.3k | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 0 | return remainder; | 1235 | 20.3k | } else { | 1236 | | | 1237 | 20.3k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 20.3k | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 20.3k | if (reduction_required) { | 1240 | 0 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 0 | } else { | 1243 | 0 | to_mul.self_reduce(); | 1244 | 0 | } | 1245 | 0 | return (*this).madd(to_mul, to_add); | 1246 | 0 | } | 1247 | 20.3k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 20.3k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 20.3k | }; | 1250 | 20.3k | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 20.3k | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 34.1k | for (auto& element : to_add) { | 1253 | 34.1k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 34.1k | } | 1255 | 20.3k | return remainder; | 1256 | 20.3k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE Line | Count | Source | 1205 | 288 | { | 1206 | 288 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 288 | Builder* ctx = context ? context : to_mul.context; | 1208 | 288 | reduction_check(); | 1209 | 288 | to_mul.reduction_check(); | 1210 | | | 1211 | 288 | uint512_t add_values(0); | 1212 | 288 | bool add_constant = true; | 1213 | | | 1214 | 288 | for (const auto& add_element : to_add) { | 1215 | 288 | add_element.reduction_check(); | 1216 | 288 | add_values += add_element.get_value(); | 1217 | 288 | add_constant = add_constant && (add_element.is_constant()); | 1218 | 288 | } | 1219 | | | 1220 | 288 | const uint1024_t left(get_value()); | 1221 | 288 | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 288 | const uint1024_t add_right(add_values); | 1223 | 288 | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 288 | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 288 | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 288 | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 288 | bigfield remainder; | 1231 | 288 | bigfield quotient; | 1232 | 288 | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 0 | return remainder; | 1235 | 288 | } else { | 1236 | | | 1237 | 288 | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 288 | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 288 | if (reduction_required) { | 1240 | 0 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 0 | } else { | 1243 | 0 | to_mul.self_reduce(); | 1244 | 0 | } | 1245 | 0 | return (*this).madd(to_mul, to_add); | 1246 | 0 | } | 1247 | 288 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 288 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 288 | }; | 1250 | 288 | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 288 | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 288 | for (auto& element : to_add) { | 1253 | 288 | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 288 | } | 1255 | 288 | return remainder; | 1256 | 288 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 1205 | 1.30k | { | 1206 | 1.30k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1207 | 1.30k | Builder* ctx = context ? context : to_mul.context; | 1208 | 1.30k | reduction_check(); | 1209 | 1.30k | to_mul.reduction_check(); | 1210 | | | 1211 | 1.30k | uint512_t add_values(0); | 1212 | 1.30k | bool add_constant = true; | 1213 | | | 1214 | 2.58k | for (const auto& add_element : to_add) { | 1215 | 2.58k | add_element.reduction_check(); | 1216 | 2.58k | add_values += add_element.get_value(); | 1217 | 2.58k | add_constant = add_constant && (add_element.is_constant()); | 1218 | 2.58k | } | 1219 | | | 1220 | 1.30k | const uint1024_t left(get_value()); | 1221 | 1.30k | const uint1024_t mul_right(to_mul.get_value()); | 1222 | 1.30k | const uint1024_t add_right(add_values); | 1223 | 1.30k | const uint1024_t modulus(target_basis.modulus); | 1224 | | | 1225 | 1.30k | const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus); | 1226 | | | 1227 | 1.30k | const uint512_t quotient_value = quotient_1024.lo; | 1228 | 1.30k | const uint512_t remainder_value = remainder_1024.lo; | 1229 | | | 1230 | 1.30k | bigfield remainder; | 1231 | 1.30k | bigfield quotient; | 1232 | 1.30k | if (is_constant() && to_mul.is_constant() && add_constant) { | 1233 | 0 | remainder = bigfield(ctx, uint256_t(remainder_value.lo)); | 1234 | 0 | return remainder; | 1235 | 1.30k | } else { | 1236 | | | 1237 | 1.30k | auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info( | 1238 | 1.30k | { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER }); | 1239 | 1.30k | if (reduction_required) { | 1240 | 0 | if (get_maximum_value() > to_mul.get_maximum_value()) { | 1241 | 0 | self_reduce(); | 1242 | 0 | } else { | 1243 | 0 | to_mul.self_reduce(); | 1244 | 0 | } | 1245 | 0 | return (*this).madd(to_mul, to_add); | 1246 | 0 | } | 1247 | 1.30k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1248 | 1.30k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1249 | 1.30k | }; | 1250 | 1.30k | unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder }); | 1251 | 1.30k | OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag()); | 1252 | 2.58k | for (auto& element : to_add) { | 1253 | 2.58k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1254 | 2.58k | } | 1255 | 1.30k | return remainder; | 1256 | 1.30k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE |
1257 | | |
1258 | | // MERGENOTE: Implementing dual_madd in terms of mult_madd following #729 |
1259 | | |
1260 | | /** |
1261 | | * @brief Performs individual reductions on the supplied elements as well as more complex reductions to prevent CRT |
1262 | | * modulus overflow and to fit the quotient inside the range proof |
1263 | | * |
1264 | | * |
1265 | | * @tparam Builder builder |
1266 | | * @tparam T basefield |
1267 | | * @param mul_left |
1268 | | * @param mul_right |
1269 | | * @param to_add |
1270 | | */ |
1271 | | template <typename Builder, typename T> |
1272 | | void bigfield<Builder, T>::perform_reductions_for_mult_madd(std::vector<bigfield>& mul_left, |
1273 | | std::vector<bigfield>& mul_right, |
1274 | | const std::vector<bigfield>& to_add) |
1275 | 370k | { |
1276 | 370k | ASSERT(mul_left.size() == mul_right.size()); |
1277 | 370k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
1278 | 370k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); |
1279 | | |
1280 | 0 | const size_t number_of_products = mul_left.size(); |
1281 | | // Get the maximum values of elements |
1282 | 0 | std::vector<uint512_t> max_values_left; |
1283 | 0 | std::vector<uint512_t> max_values_right; |
1284 | |
|
1285 | 0 | max_values_left.reserve(number_of_products); |
1286 | 0 | max_values_right.reserve(number_of_products); |
1287 | | // Do regular reduction checks for all elements |
1288 | 824k | for (auto& left_element : mul_left) { |
1289 | 824k | left_element.reduction_check(); |
1290 | 824k | max_values_left.emplace_back(left_element.get_maximum_value()); |
1291 | 824k | } |
1292 | |
|
1293 | 824k | for (auto& right_element : mul_right) { |
1294 | 824k | right_element.reduction_check(); |
1295 | 824k | max_values_right.emplace_back(right_element.get_maximum_value()); |
1296 | 824k | } |
1297 | | |
1298 | | // Perform CRT checks for the whole evaluation |
1299 | | // 1. Check if we can overflow CRT modulus |
1300 | | // 2. Check if the quotient actually fits in our range proof. |
1301 | | // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product |
1302 | | |
1303 | | // We only get the bitlength of range proof if there is no reduction |
1304 | 0 | bool reduction_required; |
1305 | 0 | reduction_required = std::get<0>( |
1306 | 0 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); |
1307 | |
|
1308 | 370k | if (reduction_required) { |
1309 | | |
1310 | | // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus |
1311 | | // For that we need to compute the maximum update - how much reducing each element is going to update the |
1312 | | // quotient. |
1313 | | // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number | |
1314 | 1 | std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates; |
1315 | | |
1316 | | // We use this lambda function before the loop and in the loop itself |
1317 | | // It computes the maximum value update from reduction of each element |
1318 | 1 | auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates, |
1319 | 1 | std::vector<bigfield>& m_left, |
1320 | 1 | std::vector<bigfield>& m_right, |
1321 | 1 | size_t number_of_products) { |
1322 | 1 | maxval_updates.resize(0); |
1323 | 1 | maxval_updates.reserve(number_of_products * 2); |
1324 | | // Compute all reduction differences |
1325 | 2 | for (size_t i = 0; i < number_of_products; i++) { |
1326 | 1 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); |
1327 | 1 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); |
1328 | 1 | uint1024_t original_product = original_left * original_right; |
1329 | 1 | if (m_left[i].is_constant()) { |
1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. |
1331 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); |
1332 | 1 | } else { |
1333 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; |
1334 | 1 | if (new_product > original_product) { |
1335 | 0 | throw_or_abort("bigfield: This should never happen"); |
1336 | 0 | } |
1337 | 1 | maxval_updates.emplace_back( |
1338 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); |
1339 | 1 | } |
1340 | 1 | if (m_right[i].is_constant()) { |
1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. |
1342 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); |
1343 | 1 | } else { |
1344 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; |
1345 | 1 | if (new_product > original_product) { |
1346 | 0 | throw_or_abort("bigfield: This should never happen"); |
1347 | 0 | } |
1348 | 1 | maxval_updates.emplace_back( |
1349 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); |
1350 | 1 | } |
1351 | 1 | } |
1352 | 1 | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m Line | Count | Source | 1321 | 1 | size_t number_of_products) { | 1322 | 1 | maxval_updates.resize(0); | 1323 | 1 | maxval_updates.reserve(number_of_products * 2); | 1324 | | // Compute all reduction differences | 1325 | 2 | for (size_t i = 0; i < number_of_products; i++) { | 1326 | 1 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); | 1327 | 1 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); | 1328 | 1 | uint1024_t original_product = original_left * original_right; | 1329 | 1 | if (m_left[i].is_constant()) { | 1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1331 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); | 1332 | 1 | } else { | 1333 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; | 1334 | 1 | if (new_product > original_product) { | 1335 | 0 | throw_or_abort("bigfield: This should never happen"); | 1336 | 0 | } | 1337 | 1 | maxval_updates.emplace_back( | 1338 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); | 1339 | 1 | } | 1340 | 1 | if (m_right[i].is_constant()) { | 1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1342 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); | 1343 | 1 | } else { | 1344 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; | 1345 | 1 | if (new_product > original_product) { | 1346 | 0 | throw_or_abort("bigfield: This should never happen"); | 1347 | 0 | } | 1348 | 1 | maxval_updates.emplace_back( | 1349 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); | 1350 | 1 | } | 1351 | 1 | } | 1352 | 1 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRS9_ISt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESaISL_EESC_SC_mE_clESO_SC_SC_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m |
1353 | | |
1354 | 1 | auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element, |
1355 | 2 | std::tuple<uint1024_t, size_t, size_t>& right_element) { |
1356 | 2 | return std::get<0>(left_element) > std::get<0>(right_element); |
1357 | 2 | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_ Line | Count | Source | 1355 | 2 | std::tuple<uint1024_t, size_t, size_t>& right_element) { | 1356 | 2 | return std::get<0>(left_element) > std::get<0>(right_element); | 1357 | 2 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRSt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESM_E_clESM_SM_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_ |
1358 | | |
1359 | | // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer |
1360 | | // gates |
1361 | | |
1362 | 2 | while (reduction_required) { |
1363 | | // Compute the possible reduction updates |
1364 | 1 | compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products); |
1365 | | |
1366 | | // Sort the vector, larger values first |
1367 | 1 | std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples); |
1368 | | |
1369 | | // We choose the largest update |
1370 | 1 | auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0]; |
1371 | 1 | if (!update_size) { |
1372 | 0 | throw_or_abort("bigfield: Can't reduce further"); |
1373 | 0 | } |
1374 | | // Reduce the larger of the multiplicands that compose the product |
1375 | 1 | if (multiplicand_index == 0) { |
1376 | 1 | mul_left[largest_update_product_index].self_reduce(); |
1377 | 1 | } else { |
1378 | 0 | mul_right[largest_update_product_index].self_reduce(); |
1379 | 0 | } |
1380 | | |
1381 | 2 | for (size_t i = 0; i < number_of_products; i++) { |
1382 | 1 | max_values_left[i] = mul_left[i].get_maximum_value(); |
1383 | 1 | max_values_right[i] = mul_right[i].get_maximum_value(); |
1384 | 1 | } |
1385 | 1 | reduction_required = std::get<0>( |
1386 | 1 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); |
1387 | 1 | } |
1388 | | |
1389 | | // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even |
1390 | | // fewer reductions, but for now this will suffice. |
1391 | 1 | } |
1392 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ Line | Count | Source | 1275 | 338k | { | 1276 | 338k | ASSERT(mul_left.size() == mul_right.size()); | 1277 | 338k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1278 | 338k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1279 | | | 1280 | 338k | const size_t number_of_products = mul_left.size(); | 1281 | | // Get the maximum values of elements | 1282 | 338k | std::vector<uint512_t> max_values_left; | 1283 | 338k | std::vector<uint512_t> max_values_right; | 1284 | | | 1285 | 338k | max_values_left.reserve(number_of_products); | 1286 | 338k | max_values_right.reserve(number_of_products); | 1287 | | // Do regular reduction checks for all elements | 1288 | 743k | for (auto& left_element : mul_left) { | 1289 | 743k | left_element.reduction_check(); | 1290 | 743k | max_values_left.emplace_back(left_element.get_maximum_value()); | 1291 | 743k | } | 1292 | | | 1293 | 743k | for (auto& right_element : mul_right) { | 1294 | 743k | right_element.reduction_check(); | 1295 | 743k | max_values_right.emplace_back(right_element.get_maximum_value()); | 1296 | 743k | } | 1297 | | | 1298 | | // Perform CRT checks for the whole evaluation | 1299 | | // 1. Check if we can overflow CRT modulus | 1300 | | // 2. Check if the quotient actually fits in our range proof. | 1301 | | // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product | 1302 | | | 1303 | | // We only get the bitlength of range proof if there is no reduction | 1304 | 338k | bool reduction_required; | 1305 | 338k | reduction_required = std::get<0>( | 1306 | 338k | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1307 | | | 1308 | 338k | if (reduction_required) { | 1309 | | | 1310 | | // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus | 1311 | | // For that we need to compute the maximum update - how much reducing each element is going to update the | 1312 | | // quotient. | 1313 | | // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number | | 1314 | 1 | std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates; | 1315 | | | 1316 | | // We use this lambda function before the loop and in the loop itself | 1317 | | // It computes the maximum value update from reduction of each element | 1318 | 1 | auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates, | 1319 | 1 | std::vector<bigfield>& m_left, | 1320 | 1 | std::vector<bigfield>& m_right, | 1321 | 1 | size_t number_of_products) { | 1322 | 1 | maxval_updates.resize(0); | 1323 | 1 | maxval_updates.reserve(number_of_products * 2); | 1324 | | // Compute all reduction differences | 1325 | 1 | for (size_t i = 0; i < number_of_products; i++) { | 1326 | 1 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); | 1327 | 1 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); | 1328 | 1 | uint1024_t original_product = original_left * original_right; | 1329 | 1 | if (m_left[i].is_constant()) { | 1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1331 | 1 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); | 1332 | 1 | } else { | 1333 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; | 1334 | 1 | if (new_product > original_product) { | 1335 | 1 | throw_or_abort("bigfield: This should never happen"); | 1336 | 1 | } | 1337 | 1 | maxval_updates.emplace_back( | 1338 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); | 1339 | 1 | } | 1340 | 1 | if (m_right[i].is_constant()) { | 1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1342 | 1 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); | 1343 | 1 | } else { | 1344 | 1 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; | 1345 | 1 | if (new_product > original_product) { | 1346 | 1 | throw_or_abort("bigfield: This should never happen"); | 1347 | 1 | } | 1348 | 1 | maxval_updates.emplace_back( | 1349 | 1 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); | 1350 | 1 | } | 1351 | 1 | } | 1352 | 1 | }; | 1353 | | | 1354 | 1 | auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element, | 1355 | 1 | std::tuple<uint1024_t, size_t, size_t>& right_element) { | 1356 | 1 | return std::get<0>(left_element) > std::get<0>(right_element); | 1357 | 1 | }; | 1358 | | | 1359 | | // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer | 1360 | | // gates | 1361 | | | 1362 | 2 | while (reduction_required) { | 1363 | | // Compute the possible reduction updates | 1364 | 1 | compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products); | 1365 | | | 1366 | | // Sort the vector, larger values first | 1367 | 1 | std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples); | 1368 | | | 1369 | | // We choose the largest update | 1370 | 1 | auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0]; | 1371 | 1 | if (!update_size) { | 1372 | 0 | throw_or_abort("bigfield: Can't reduce further"); | 1373 | 0 | } | 1374 | | // Reduce the larger of the multiplicands that compose the product | 1375 | 1 | if (multiplicand_index == 0) { | 1376 | 1 | mul_left[largest_update_product_index].self_reduce(); | 1377 | 1 | } else { | 1378 | 0 | mul_right[largest_update_product_index].self_reduce(); | 1379 | 0 | } | 1380 | | | 1381 | 2 | for (size_t i = 0; i < number_of_products; i++) { | 1382 | 1 | max_values_left[i] = mul_left[i].get_maximum_value(); | 1383 | 1 | max_values_right[i] = mul_right[i].get_maximum_value(); | 1384 | 1 | } | 1385 | 1 | reduction_required = std::get<0>( | 1386 | 1 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1387 | 1 | } | 1388 | | | 1389 | | // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even | 1390 | | // fewer reductions, but for now this will suffice. | 1391 | 1 | } | 1392 | 338k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ Line | Count | Source | 1275 | 1.29k | { | 1276 | 1.29k | ASSERT(mul_left.size() == mul_right.size()); | 1277 | 1.29k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1278 | 1.29k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1279 | | | 1280 | 1.29k | const size_t number_of_products = mul_left.size(); | 1281 | | // Get the maximum values of elements | 1282 | 1.29k | std::vector<uint512_t> max_values_left; | 1283 | 1.29k | std::vector<uint512_t> max_values_right; | 1284 | | | 1285 | 1.29k | max_values_left.reserve(number_of_products); | 1286 | 1.29k | max_values_right.reserve(number_of_products); | 1287 | | // Do regular reduction checks for all elements | 1288 | 3.15k | for (auto& left_element : mul_left) { | 1289 | 3.15k | left_element.reduction_check(); | 1290 | 3.15k | max_values_left.emplace_back(left_element.get_maximum_value()); | 1291 | 3.15k | } | 1292 | | | 1293 | 3.15k | for (auto& right_element : mul_right) { | 1294 | 3.15k | right_element.reduction_check(); | 1295 | 3.15k | max_values_right.emplace_back(right_element.get_maximum_value()); | 1296 | 3.15k | } | 1297 | | | 1298 | | // Perform CRT checks for the whole evaluation | 1299 | | // 1. Check if we can overflow CRT modulus | 1300 | | // 2. Check if the quotient actually fits in our range proof. | 1301 | | // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product | 1302 | | | 1303 | | // We only get the bitlength of range proof if there is no reduction | 1304 | 1.29k | bool reduction_required; | 1305 | 1.29k | reduction_required = std::get<0>( | 1306 | 1.29k | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1307 | | | 1308 | 1.29k | if (reduction_required) { | 1309 | | | 1310 | | // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus | 1311 | | // For that we need to compute the maximum update - how much reducing each element is going to update the | 1312 | | // quotient. | 1313 | | // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number | | 1314 | 0 | std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates; | 1315 | | | 1316 | | // We use this lambda function before the loop and in the loop itself | 1317 | | // It computes the maximum value update from reduction of each element | 1318 | 0 | auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates, | 1319 | 0 | std::vector<bigfield>& m_left, | 1320 | 0 | std::vector<bigfield>& m_right, | 1321 | 0 | size_t number_of_products) { | 1322 | 0 | maxval_updates.resize(0); | 1323 | 0 | maxval_updates.reserve(number_of_products * 2); | 1324 | | // Compute all reduction differences | 1325 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1326 | 0 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); | 1327 | 0 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); | 1328 | 0 | uint1024_t original_product = original_left * original_right; | 1329 | 0 | if (m_left[i].is_constant()) { | 1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1331 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); | 1332 | 0 | } else { | 1333 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; | 1334 | 0 | if (new_product > original_product) { | 1335 | 0 | throw_or_abort("bigfield: This should never happen"); | 1336 | 0 | } | 1337 | 0 | maxval_updates.emplace_back( | 1338 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); | 1339 | 0 | } | 1340 | 0 | if (m_right[i].is_constant()) { | 1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1342 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); | 1343 | 0 | } else { | 1344 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; | 1345 | 0 | if (new_product > original_product) { | 1346 | 0 | throw_or_abort("bigfield: This should never happen"); | 1347 | 0 | } | 1348 | 0 | maxval_updates.emplace_back( | 1349 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); | 1350 | 0 | } | 1351 | 0 | } | 1352 | 0 | }; | 1353 | |
| 1354 | 0 | auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element, | 1355 | 0 | std::tuple<uint1024_t, size_t, size_t>& right_element) { | 1356 | 0 | return std::get<0>(left_element) > std::get<0>(right_element); | 1357 | 0 | }; | 1358 | | | 1359 | | // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer | 1360 | | // gates | 1361 | |
| 1362 | 0 | while (reduction_required) { | 1363 | | // Compute the possible reduction updates | 1364 | 0 | compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products); | 1365 | | | 1366 | | // Sort the vector, larger values first | 1367 | 0 | std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples); | 1368 | | | 1369 | | // We choose the largest update | 1370 | 0 | auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0]; | 1371 | 0 | if (!update_size) { | 1372 | 0 | throw_or_abort("bigfield: Can't reduce further"); | 1373 | 0 | } | 1374 | | // Reduce the larger of the multiplicands that compose the product | 1375 | 0 | if (multiplicand_index == 0) { | 1376 | 0 | mul_left[largest_update_product_index].self_reduce(); | 1377 | 0 | } else { | 1378 | 0 | mul_right[largest_update_product_index].self_reduce(); | 1379 | 0 | } | 1380 | |
| 1381 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1382 | 0 | max_values_left[i] = mul_left[i].get_maximum_value(); | 1383 | 0 | max_values_right[i] = mul_right[i].get_maximum_value(); | 1384 | 0 | } | 1385 | 0 | reduction_required = std::get<0>( | 1386 | 0 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1387 | 0 | } | 1388 | | | 1389 | | // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even | 1390 | | // fewer reductions, but for now this will suffice. | 1391 | 0 | } | 1392 | 1.29k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ Line | Count | Source | 1275 | 28.3k | { | 1276 | 28.3k | ASSERT(mul_left.size() == mul_right.size()); | 1277 | 28.3k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1278 | 28.3k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1279 | | | 1280 | 28.3k | const size_t number_of_products = mul_left.size(); | 1281 | | // Get the maximum values of elements | 1282 | 28.3k | std::vector<uint512_t> max_values_left; | 1283 | 28.3k | std::vector<uint512_t> max_values_right; | 1284 | | | 1285 | 28.3k | max_values_left.reserve(number_of_products); | 1286 | 28.3k | max_values_right.reserve(number_of_products); | 1287 | | // Do regular reduction checks for all elements | 1288 | 70.5k | for (auto& left_element : mul_left) { | 1289 | 70.5k | left_element.reduction_check(); | 1290 | 70.5k | max_values_left.emplace_back(left_element.get_maximum_value()); | 1291 | 70.5k | } | 1292 | | | 1293 | 70.5k | for (auto& right_element : mul_right) { | 1294 | 70.5k | right_element.reduction_check(); | 1295 | 70.5k | max_values_right.emplace_back(right_element.get_maximum_value()); | 1296 | 70.5k | } | 1297 | | | 1298 | | // Perform CRT checks for the whole evaluation | 1299 | | // 1. Check if we can overflow CRT modulus | 1300 | | // 2. Check if the quotient actually fits in our range proof. | 1301 | | // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product | 1302 | | | 1303 | | // We only get the bitlength of range proof if there is no reduction | 1304 | 28.3k | bool reduction_required; | 1305 | 28.3k | reduction_required = std::get<0>( | 1306 | 28.3k | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1307 | | | 1308 | 28.3k | if (reduction_required) { | 1309 | | | 1310 | | // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus | 1311 | | // For that we need to compute the maximum update - how much reducing each element is going to update the | 1312 | | // quotient. | 1313 | | // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number | | 1314 | 0 | std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates; | 1315 | | | 1316 | | // We use this lambda function before the loop and in the loop itself | 1317 | | // It computes the maximum value update from reduction of each element | 1318 | 0 | auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates, | 1319 | 0 | std::vector<bigfield>& m_left, | 1320 | 0 | std::vector<bigfield>& m_right, | 1321 | 0 | size_t number_of_products) { | 1322 | 0 | maxval_updates.resize(0); | 1323 | 0 | maxval_updates.reserve(number_of_products * 2); | 1324 | | // Compute all reduction differences | 1325 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1326 | 0 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); | 1327 | 0 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); | 1328 | 0 | uint1024_t original_product = original_left * original_right; | 1329 | 0 | if (m_left[i].is_constant()) { | 1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1331 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); | 1332 | 0 | } else { | 1333 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; | 1334 | 0 | if (new_product > original_product) { | 1335 | 0 | throw_or_abort("bigfield: This should never happen"); | 1336 | 0 | } | 1337 | 0 | maxval_updates.emplace_back( | 1338 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); | 1339 | 0 | } | 1340 | 0 | if (m_right[i].is_constant()) { | 1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1342 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); | 1343 | 0 | } else { | 1344 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; | 1345 | 0 | if (new_product > original_product) { | 1346 | 0 | throw_or_abort("bigfield: This should never happen"); | 1347 | 0 | } | 1348 | 0 | maxval_updates.emplace_back( | 1349 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); | 1350 | 0 | } | 1351 | 0 | } | 1352 | 0 | }; | 1353 | |
| 1354 | 0 | auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element, | 1355 | 0 | std::tuple<uint1024_t, size_t, size_t>& right_element) { | 1356 | 0 | return std::get<0>(left_element) > std::get<0>(right_element); | 1357 | 0 | }; | 1358 | | | 1359 | | // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer | 1360 | | // gates | 1361 | |
| 1362 | 0 | while (reduction_required) { | 1363 | | // Compute the possible reduction updates | 1364 | 0 | compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products); | 1365 | | | 1366 | | // Sort the vector, larger values first | 1367 | 0 | std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples); | 1368 | | | 1369 | | // We choose the largest update | 1370 | 0 | auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0]; | 1371 | 0 | if (!update_size) { | 1372 | 0 | throw_or_abort("bigfield: Can't reduce further"); | 1373 | 0 | } | 1374 | | // Reduce the larger of the multiplicands that compose the product | 1375 | 0 | if (multiplicand_index == 0) { | 1376 | 0 | mul_left[largest_update_product_index].self_reduce(); | 1377 | 0 | } else { | 1378 | 0 | mul_right[largest_update_product_index].self_reduce(); | 1379 | 0 | } | 1380 | |
| 1381 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1382 | 0 | max_values_left[i] = mul_left[i].get_maximum_value(); | 1383 | 0 | max_values_right[i] = mul_right[i].get_maximum_value(); | 1384 | 0 | } | 1385 | 0 | reduction_required = std::get<0>( | 1386 | 0 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1387 | 0 | } | 1388 | | | 1389 | | // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even | 1390 | | // fewer reductions, but for now this will suffice. | 1391 | 0 | } | 1392 | 28.3k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ Line | Count | Source | 1275 | 2.23k | { | 1276 | 2.23k | ASSERT(mul_left.size() == mul_right.size()); | 1277 | 2.23k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1278 | 2.23k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1279 | | | 1280 | 2.23k | const size_t number_of_products = mul_left.size(); | 1281 | | // Get the maximum values of elements | 1282 | 2.23k | std::vector<uint512_t> max_values_left; | 1283 | 2.23k | std::vector<uint512_t> max_values_right; | 1284 | | | 1285 | 2.23k | max_values_left.reserve(number_of_products); | 1286 | 2.23k | max_values_right.reserve(number_of_products); | 1287 | | // Do regular reduction checks for all elements | 1288 | 7.01k | for (auto& left_element : mul_left) { | 1289 | 7.01k | left_element.reduction_check(); | 1290 | 7.01k | max_values_left.emplace_back(left_element.get_maximum_value()); | 1291 | 7.01k | } | 1292 | | | 1293 | 7.01k | for (auto& right_element : mul_right) { | 1294 | 7.01k | right_element.reduction_check(); | 1295 | 7.01k | max_values_right.emplace_back(right_element.get_maximum_value()); | 1296 | 7.01k | } | 1297 | | | 1298 | | // Perform CRT checks for the whole evaluation | 1299 | | // 1. Check if we can overflow CRT modulus | 1300 | | // 2. Check if the quotient actually fits in our range proof. | 1301 | | // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product | 1302 | | | 1303 | | // We only get the bitlength of range proof if there is no reduction | 1304 | 2.23k | bool reduction_required; | 1305 | 2.23k | reduction_required = std::get<0>( | 1306 | 2.23k | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1307 | | | 1308 | 2.23k | if (reduction_required) { | 1309 | | | 1310 | | // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus | 1311 | | // For that we need to compute the maximum update - how much reducing each element is going to update the | 1312 | | // quotient. | 1313 | | // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number | | 1314 | 0 | std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates; | 1315 | | | 1316 | | // We use this lambda function before the loop and in the loop itself | 1317 | | // It computes the maximum value update from reduction of each element | 1318 | 0 | auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates, | 1319 | 0 | std::vector<bigfield>& m_left, | 1320 | 0 | std::vector<bigfield>& m_right, | 1321 | 0 | size_t number_of_products) { | 1322 | 0 | maxval_updates.resize(0); | 1323 | 0 | maxval_updates.reserve(number_of_products * 2); | 1324 | | // Compute all reduction differences | 1325 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1326 | 0 | uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value()); | 1327 | 0 | uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value()); | 1328 | 0 | uint1024_t original_product = original_left * original_right; | 1329 | 0 | if (m_left[i].is_constant()) { | 1330 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1331 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0)); | 1332 | 0 | } else { | 1333 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right; | 1334 | 0 | if (new_product > original_product) { | 1335 | 0 | throw_or_abort("bigfield: This should never happen"); | 1336 | 0 | } | 1337 | 0 | maxval_updates.emplace_back( | 1338 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0)); | 1339 | 0 | } | 1340 | 0 | if (m_right[i].is_constant()) { | 1341 | | // If the multiplicand is constant, we can't reduce it, so the update is 0. | 1342 | 0 | maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1)); | 1343 | 0 | } else { | 1344 | 0 | uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left; | 1345 | 0 | if (new_product > original_product) { | 1346 | 0 | throw_or_abort("bigfield: This should never happen"); | 1347 | 0 | } | 1348 | 0 | maxval_updates.emplace_back( | 1349 | 0 | std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1)); | 1350 | 0 | } | 1351 | 0 | } | 1352 | 0 | }; | 1353 | |
| 1354 | 0 | auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element, | 1355 | 0 | std::tuple<uint1024_t, size_t, size_t>& right_element) { | 1356 | 0 | return std::get<0>(left_element) > std::get<0>(right_element); | 1357 | 0 | }; | 1358 | | | 1359 | | // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer | 1360 | | // gates | 1361 | |
| 1362 | 0 | while (reduction_required) { | 1363 | | // Compute the possible reduction updates | 1364 | 0 | compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products); | 1365 | | | 1366 | | // Sort the vector, larger values first | 1367 | 0 | std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples); | 1368 | | | 1369 | | // We choose the largest update | 1370 | 0 | auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0]; | 1371 | 0 | if (!update_size) { | 1372 | 0 | throw_or_abort("bigfield: Can't reduce further"); | 1373 | 0 | } | 1374 | | // Reduce the larger of the multiplicands that compose the product | 1375 | 0 | if (multiplicand_index == 0) { | 1376 | 0 | mul_left[largest_update_product_index].self_reduce(); | 1377 | 0 | } else { | 1378 | 0 | mul_right[largest_update_product_index].self_reduce(); | 1379 | 0 | } | 1380 | |
| 1381 | 0 | for (size_t i = 0; i < number_of_products; i++) { | 1382 | 0 | max_values_left[i] = mul_left[i].get_maximum_value(); | 1383 | 0 | max_values_right[i] = mul_right[i].get_maximum_value(); | 1384 | 0 | } | 1385 | 0 | reduction_required = std::get<0>( | 1386 | 0 | get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER })); | 1387 | 0 | } | 1388 | | | 1389 | | // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even | 1390 | | // fewer reductions, but for now this will suffice. | 1391 | 0 | } | 1392 | 2.23k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ |
1393 | | |
1394 | | /** |
1395 | | * Evaluate the sum of products and additional values safely. |
1396 | | * |
1397 | | * @param mul_left Vector of bigfield multiplicands |
1398 | | * @param mul_right Vector of bigfield multipliers |
1399 | | * @param to_add Vector of bigfield elements to add to the sum of products |
1400 | | * |
1401 | | * @return A reduced value that is the sum of all products and to_add values |
1402 | | * */ |
1403 | | template <typename Builder, typename T> |
1404 | | bigfield<Builder, T> bigfield<Builder, T>::mult_madd(const std::vector<bigfield>& mul_left, |
1405 | | const std::vector<bigfield>& mul_right, |
1406 | | const std::vector<bigfield>& to_add, |
1407 | | bool fix_remainder_to_zero) |
1408 | 370k | { |
1409 | 370k | ASSERT(mul_left.size() == mul_right.size()); |
1410 | 370k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); |
1411 | 370k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
1412 | | |
1413 | 0 | std::vector<bigfield> mutable_mul_left(mul_left); |
1414 | 0 | std::vector<bigfield> mutable_mul_right(mul_right); |
1415 | |
|
1416 | 0 | const size_t number_of_products = mul_left.size(); |
1417 | |
|
1418 | 0 | const uint1024_t modulus(target_basis.modulus); |
1419 | 0 | uint1024_t worst_case_product_sum(0); |
1420 | 0 | uint1024_t add_right_constant_sum(0); |
1421 | | |
1422 | | // First we do all constant optimizations |
1423 | 0 | bool add_constant = true; |
1424 | 0 | std::vector<bigfield> new_to_add; |
1425 | |
|
1426 | 0 | OriginTag new_tag{}; |
1427 | | // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge) |
1428 | 824k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { |
1429 | 824k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); |
1430 | 824k | } |
1431 | 653k | for (auto& element : to_add) { |
1432 | 653k | new_tag = OriginTag(new_tag, element.get_origin_tag()); |
1433 | 653k | } |
1434 | |
|
1435 | 653k | for (const auto& add_element : to_add) { |
1436 | 653k | add_element.reduction_check(); |
1437 | 653k | if (add_element.is_constant()) { |
1438 | 86 | add_right_constant_sum += uint1024_t(add_element.get_value()); |
1439 | 653k | } else { |
1440 | 653k | add_constant = false; |
1441 | 653k | new_to_add.push_back(add_element); |
1442 | 653k | } |
1443 | 653k | } |
1444 | | |
1445 | | // Compute the product sum |
1446 | | // Optimize constant use |
1447 | 0 | uint1024_t sum_of_constant_products(0); |
1448 | 0 | std::vector<bigfield> new_input_left; |
1449 | 0 | std::vector<bigfield> new_input_right; |
1450 | 0 | bool product_sum_constant = true; |
1451 | 1.19M | for (size_t i = 0; i < number_of_products; i++) { |
1452 | 824k | if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) { |
1453 | | // If constant, just add to the sum |
1454 | 0 | sum_of_constant_products += |
1455 | 0 | uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value()); |
1456 | 824k | } else { |
1457 | | // If not, add to nonconstant sum and remember the elements |
1458 | 824k | new_input_left.push_back(mutable_mul_left[i]); |
1459 | 824k | new_input_right.push_back(mutable_mul_right[i]); |
1460 | 824k | product_sum_constant = false; |
1461 | 824k | } |
1462 | 824k | } |
1463 | |
|
1464 | 0 | Builder* ctx = nullptr; |
1465 | | // Search through all multiplicands on the left |
1466 | 370k | for (auto& el : mutable_mul_left) { |
1467 | 370k | if (el.context) { |
1468 | 370k | ctx = el.context; |
1469 | 370k | break; |
1470 | 370k | } |
1471 | 370k | } |
1472 | | // And on the right |
1473 | 370k | if (!ctx) { |
1474 | 1 | for (auto& el : mutable_mul_right) { |
1475 | 0 | if (el.context) { |
1476 | 0 | ctx = el.context; |
1477 | 0 | break; |
1478 | 0 | } |
1479 | 0 | } |
1480 | 1 | } |
1481 | 370k | if (product_sum_constant) { |
1482 | 1 | if (add_constant) { |
1483 | | // Simply return the constant, no need unsafe_multiply_add |
1484 | 1 | const auto [quotient_1024, remainder_1024] = |
1485 | 1 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); |
1486 | 1 | ASSERT(!fix_remainder_to_zero || remainder_1024 == 0); |
1487 | 0 | auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); |
1488 | 0 | result.set_origin_tag(new_tag); |
1489 | 0 | return result; |
1490 | 1 | } else { |
1491 | 0 | const auto [quotient_1024, remainder_1024] = |
1492 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); |
1493 | 0 | uint256_t remainder_value = remainder_1024.lo.lo; |
1494 | 0 | bigfield result; |
1495 | 0 | if (remainder_value == uint256_t(0)) { |
1496 | | // No need to add extra term to new_to_add |
1497 | 0 | result = sum(new_to_add); |
1498 | 0 | } else { |
1499 | | // Add the constant term |
1500 | 0 | new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value))); |
1501 | 0 | result = sum(new_to_add); |
1502 | 0 | } |
1503 | 0 | if (fix_remainder_to_zero) { |
1504 | 0 | result.self_reduce(); |
1505 | 0 | result.assert_equal(zero()); |
1506 | 0 | } |
1507 | 0 | result.set_origin_tag(new_tag); |
1508 | 0 | return result; |
1509 | 0 | } |
1510 | 1 | } |
1511 | | |
1512 | | // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions, |
1513 | | // etc |
1514 | | |
1515 | | // Compute the constant term we're adding |
1516 | 370k | const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus); |
1517 | 370k | const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo; |
1518 | | |
1519 | 370k | if (constant_part_remainder_256 != uint256_t(0)) { |
1520 | 86 | new_to_add.push_back(bigfield(ctx, constant_part_remainder_256)); |
1521 | 86 | } |
1522 | | // Compute added sum |
1523 | 370k | uint1024_t add_right_final_sum(0); |
1524 | 370k | uint1024_t add_right_maximum(0); |
1525 | 653k | for (const auto& add_element : new_to_add) { |
1526 | | // Technically not needed, but better to leave just in case |
1527 | 653k | add_element.reduction_check(); |
1528 | 653k | add_right_final_sum += uint1024_t(add_element.get_value()); |
1529 | | |
1530 | 653k | add_right_maximum += uint1024_t(add_element.get_maximum_value()); |
1531 | 653k | } |
1532 | 370k | const size_t final_number_of_products = new_input_left.size(); |
1533 | | |
1534 | | // We need to check if it is possible to reduce the products enough |
1535 | 370k | worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) * |
1536 | 370k | uint1024_t(DEFAULT_MAXIMUM_REMAINDER); |
1537 | | |
1538 | | // Check that we can actually reduce the products enough, this assert will probably never get triggered |
1539 | 370k | ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product()); |
1540 | | |
1541 | | // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check |
1542 | | // if we need to reduce something |
1543 | 0 | perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add); |
1544 | 0 | uint1024_t sum_of_products_final(0); |
1545 | 1.19M | for (size_t i = 0; i < final_number_of_products; i++) { |
1546 | 824k | sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value()); |
1547 | 824k | } |
1548 | | |
1549 | | // Get the number of range proof bits for the quotient |
1550 | 0 | const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER }); |
1551 | | |
1552 | | // Compute the quotient and remainder |
1553 | 0 | const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus); |
1554 | | |
1555 | | // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is |
1556 | |
|
1557 | 370k | if (fix_remainder_to_zero) { |
1558 | | // This is not the only check. Circuit check is coming later :) |
1559 | 341k | ASSERT(remainder_1024.lo == uint512_t(0)); |
1560 | 341k | } |
1561 | 0 | const uint512_t quotient_value = quotient_1024.lo; |
1562 | 0 | const uint512_t remainder_value = remainder_1024.lo; |
1563 | |
|
1564 | 0 | bigfield remainder; |
1565 | 0 | bigfield quotient; |
1566 | | // Constrain quotient to mitigate CRT overflow attacks |
1567 | 0 | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); |
1568 | |
|
1569 | 370k | if (fix_remainder_to_zero) { |
1570 | 341k | remainder = zero(); |
1571 | | // remainder needs to be defined as wire value and not selector values to satisfy |
1572 | | // Ultra's bigfield custom gates |
1573 | 341k | remainder.convert_constant_to_fixed_witness(ctx); |
1574 | 341k | } else { |
1575 | 28.6k | remainder = create_from_u512_as_witness(ctx, remainder_value); |
1576 | 28.6k | } |
1577 | |
|
1578 | 0 | unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder }); |
1579 | |
|
1580 | 0 | remainder.set_origin_tag(new_tag); |
1581 | 0 | return remainder; |
1582 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b Line | Count | Source | 1408 | 338k | { | 1409 | 338k | ASSERT(mul_left.size() == mul_right.size()); | 1410 | 338k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1411 | 338k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1412 | | | 1413 | 338k | std::vector<bigfield> mutable_mul_left(mul_left); | 1414 | 338k | std::vector<bigfield> mutable_mul_right(mul_right); | 1415 | | | 1416 | 338k | const size_t number_of_products = mul_left.size(); | 1417 | | | 1418 | 338k | const uint1024_t modulus(target_basis.modulus); | 1419 | 338k | uint1024_t worst_case_product_sum(0); | 1420 | 338k | uint1024_t add_right_constant_sum(0); | 1421 | | | 1422 | | // First we do all constant optimizations | 1423 | 338k | bool add_constant = true; | 1424 | 338k | std::vector<bigfield> new_to_add; | 1425 | | | 1426 | 338k | OriginTag new_tag{}; | 1427 | | // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge) | 1428 | 743k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1429 | 743k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1430 | 743k | } | 1431 | 615k | for (auto& element : to_add) { | 1432 | 615k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1433 | 615k | } | 1434 | | | 1435 | 615k | for (const auto& add_element : to_add) { | 1436 | 615k | add_element.reduction_check(); | 1437 | 615k | if (add_element.is_constant()) { | 1438 | 79 | add_right_constant_sum += uint1024_t(add_element.get_value()); | 1439 | 615k | } else { | 1440 | 615k | add_constant = false; | 1441 | 615k | new_to_add.push_back(add_element); | 1442 | 615k | } | 1443 | 615k | } | 1444 | | | 1445 | | // Compute the product sum | 1446 | | // Optimize constant use | 1447 | 338k | uint1024_t sum_of_constant_products(0); | 1448 | 338k | std::vector<bigfield> new_input_left; | 1449 | 338k | std::vector<bigfield> new_input_right; | 1450 | 338k | bool product_sum_constant = true; | 1451 | 1.08M | for (size_t i = 0; i < number_of_products; i++) { | 1452 | 743k | if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) { | 1453 | | // If constant, just add to the sum | 1454 | 0 | sum_of_constant_products += | 1455 | 0 | uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value()); | 1456 | 743k | } else { | 1457 | | // If not, add to nonconstant sum and remember the elements | 1458 | 743k | new_input_left.push_back(mutable_mul_left[i]); | 1459 | 743k | new_input_right.push_back(mutable_mul_right[i]); | 1460 | 743k | product_sum_constant = false; | 1461 | 743k | } | 1462 | 743k | } | 1463 | | | 1464 | 338k | Builder* ctx = nullptr; | 1465 | | // Search through all multiplicands on the left | 1466 | 338k | for (auto& el : mutable_mul_left) { | 1467 | 338k | if (el.context) { | 1468 | 338k | ctx = el.context; | 1469 | 338k | break; | 1470 | 338k | } | 1471 | 338k | } | 1472 | | // And on the right | 1473 | 338k | if (!ctx) { | 1474 | 1 | for (auto& el : mutable_mul_right) { | 1475 | 0 | if (el.context) { | 1476 | 0 | ctx = el.context; | 1477 | 0 | break; | 1478 | 0 | } | 1479 | 0 | } | 1480 | 1 | } | 1481 | 338k | if (product_sum_constant) { | 1482 | 1 | if (add_constant) { | 1483 | | // Simply return the constant, no need unsafe_multiply_add | 1484 | 1 | const auto [quotient_1024, remainder_1024] = | 1485 | 1 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1486 | 1 | ASSERT(!fix_remainder_to_zero || remainder_1024 == 0); | 1487 | 1 | auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1488 | 1 | result.set_origin_tag(new_tag); | 1489 | 1 | return result; | 1490 | 1 | } else { | 1491 | 0 | const auto [quotient_1024, remainder_1024] = | 1492 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1493 | 0 | uint256_t remainder_value = remainder_1024.lo.lo; | 1494 | 0 | bigfield result; | 1495 | 0 | if (remainder_value == uint256_t(0)) { | 1496 | | // No need to add extra term to new_to_add | 1497 | 0 | result = sum(new_to_add); | 1498 | 0 | } else { | 1499 | | // Add the constant term | 1500 | 0 | new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value))); | 1501 | 0 | result = sum(new_to_add); | 1502 | 0 | } | 1503 | 0 | if (fix_remainder_to_zero) { | 1504 | 0 | result.self_reduce(); | 1505 | 0 | result.assert_equal(zero()); | 1506 | 0 | } | 1507 | 0 | result.set_origin_tag(new_tag); | 1508 | 0 | return result; | 1509 | 0 | } | 1510 | 1 | } | 1511 | | | 1512 | | // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions, | 1513 | | // etc | 1514 | | | 1515 | | // Compute the constant term we're adding | 1516 | 338k | const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1517 | 338k | const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo; | 1518 | | | 1519 | 338k | if (constant_part_remainder_256 != uint256_t(0)) { | 1520 | 79 | new_to_add.push_back(bigfield(ctx, constant_part_remainder_256)); | 1521 | 79 | } | 1522 | | // Compute added sum | 1523 | 338k | uint1024_t add_right_final_sum(0); | 1524 | 338k | uint1024_t add_right_maximum(0); | 1525 | 615k | for (const auto& add_element : new_to_add) { | 1526 | | // Technically not needed, but better to leave just in case | 1527 | 615k | add_element.reduction_check(); | 1528 | 615k | add_right_final_sum += uint1024_t(add_element.get_value()); | 1529 | | | 1530 | 615k | add_right_maximum += uint1024_t(add_element.get_maximum_value()); | 1531 | 615k | } | 1532 | 338k | const size_t final_number_of_products = new_input_left.size(); | 1533 | | | 1534 | | // We need to check if it is possible to reduce the products enough | 1535 | 338k | worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) * | 1536 | 338k | uint1024_t(DEFAULT_MAXIMUM_REMAINDER); | 1537 | | | 1538 | | // Check that we can actually reduce the products enough, this assert will probably never get triggered | 1539 | 338k | ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product()); | 1540 | | | 1541 | | // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check | 1542 | | // if we need to reduce something | 1543 | 338k | perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add); | 1544 | 338k | uint1024_t sum_of_products_final(0); | 1545 | 1.08M | for (size_t i = 0; i < final_number_of_products; i++) { | 1546 | 743k | sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value()); | 1547 | 743k | } | 1548 | | | 1549 | | // Get the number of range proof bits for the quotient | 1550 | 338k | const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER }); | 1551 | | | 1552 | | // Compute the quotient and remainder | 1553 | 338k | const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus); | 1554 | | | 1555 | | // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is | 1556 | | | 1557 | 338k | if (fix_remainder_to_zero) { | 1558 | | // This is not the only check. Circuit check is coming later :) | 1559 | 314k | ASSERT(remainder_1024.lo == uint512_t(0)); | 1560 | 314k | } | 1561 | 338k | const uint512_t quotient_value = quotient_1024.lo; | 1562 | 338k | const uint512_t remainder_value = remainder_1024.lo; | 1563 | | | 1564 | 338k | bigfield remainder; | 1565 | 338k | bigfield quotient; | 1566 | | // Constrain quotient to mitigate CRT overflow attacks | 1567 | 338k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1568 | | | 1569 | 338k | if (fix_remainder_to_zero) { | 1570 | 314k | remainder = zero(); | 1571 | | // remainder needs to be defined as wire value and not selector values to satisfy | 1572 | | // Ultra's bigfield custom gates | 1573 | 314k | remainder.convert_constant_to_fixed_witness(ctx); | 1574 | 314k | } else { | 1575 | 23.5k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1576 | 23.5k | } | 1577 | | | 1578 | 338k | unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder }); | 1579 | | | 1580 | 338k | remainder.set_origin_tag(new_tag); | 1581 | 338k | return remainder; | 1582 | 338k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b Line | Count | Source | 1408 | 1.29k | { | 1409 | 1.29k | ASSERT(mul_left.size() == mul_right.size()); | 1410 | 1.29k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1411 | 1.29k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1412 | | | 1413 | 1.29k | std::vector<bigfield> mutable_mul_left(mul_left); | 1414 | 1.29k | std::vector<bigfield> mutable_mul_right(mul_right); | 1415 | | | 1416 | 1.29k | const size_t number_of_products = mul_left.size(); | 1417 | | | 1418 | 1.29k | const uint1024_t modulus(target_basis.modulus); | 1419 | 1.29k | uint1024_t worst_case_product_sum(0); | 1420 | 1.29k | uint1024_t add_right_constant_sum(0); | 1421 | | | 1422 | | // First we do all constant optimizations | 1423 | 1.29k | bool add_constant = true; | 1424 | 1.29k | std::vector<bigfield> new_to_add; | 1425 | | | 1426 | 1.29k | OriginTag new_tag{}; | 1427 | | // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge) | 1428 | 3.15k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1429 | 3.15k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1430 | 3.15k | } | 1431 | 1.37k | for (auto& element : to_add) { | 1432 | 1.37k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1433 | 1.37k | } | 1434 | | | 1435 | 1.37k | for (const auto& add_element : to_add) { | 1436 | 1.37k | add_element.reduction_check(); | 1437 | 1.37k | if (add_element.is_constant()) { | 1438 | 3 | add_right_constant_sum += uint1024_t(add_element.get_value()); | 1439 | 1.37k | } else { | 1440 | 1.37k | add_constant = false; | 1441 | 1.37k | new_to_add.push_back(add_element); | 1442 | 1.37k | } | 1443 | 1.37k | } | 1444 | | | 1445 | | // Compute the product sum | 1446 | | // Optimize constant use | 1447 | 1.29k | uint1024_t sum_of_constant_products(0); | 1448 | 1.29k | std::vector<bigfield> new_input_left; | 1449 | 1.29k | std::vector<bigfield> new_input_right; | 1450 | 1.29k | bool product_sum_constant = true; | 1451 | 4.44k | for (size_t i = 0; i < number_of_products; i++) { | 1452 | 3.15k | if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) { | 1453 | | // If constant, just add to the sum | 1454 | 0 | sum_of_constant_products += | 1455 | 0 | uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value()); | 1456 | 3.15k | } else { | 1457 | | // If not, add to nonconstant sum and remember the elements | 1458 | 3.15k | new_input_left.push_back(mutable_mul_left[i]); | 1459 | 3.15k | new_input_right.push_back(mutable_mul_right[i]); | 1460 | 3.15k | product_sum_constant = false; | 1461 | 3.15k | } | 1462 | 3.15k | } | 1463 | | | 1464 | 1.29k | Builder* ctx = nullptr; | 1465 | | // Search through all multiplicands on the left | 1466 | 1.29k | for (auto& el : mutable_mul_left) { | 1467 | 1.29k | if (el.context) { | 1468 | 1.29k | ctx = el.context; | 1469 | 1.29k | break; | 1470 | 1.29k | } | 1471 | 1.29k | } | 1472 | | // And on the right | 1473 | 1.29k | if (!ctx) { | 1474 | 0 | for (auto& el : mutable_mul_right) { | 1475 | 0 | if (el.context) { | 1476 | 0 | ctx = el.context; | 1477 | 0 | break; | 1478 | 0 | } | 1479 | 0 | } | 1480 | 0 | } | 1481 | 1.29k | if (product_sum_constant) { | 1482 | 0 | if (add_constant) { | 1483 | | // Simply return the constant, no need unsafe_multiply_add | 1484 | 0 | const auto [quotient_1024, remainder_1024] = | 1485 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1486 | 0 | ASSERT(!fix_remainder_to_zero || remainder_1024 == 0); | 1487 | 0 | auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1488 | 0 | result.set_origin_tag(new_tag); | 1489 | 0 | return result; | 1490 | 0 | } else { | 1491 | 0 | const auto [quotient_1024, remainder_1024] = | 1492 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1493 | 0 | uint256_t remainder_value = remainder_1024.lo.lo; | 1494 | 0 | bigfield result; | 1495 | 0 | if (remainder_value == uint256_t(0)) { | 1496 | | // No need to add extra term to new_to_add | 1497 | 0 | result = sum(new_to_add); | 1498 | 0 | } else { | 1499 | | // Add the constant term | 1500 | 0 | new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value))); | 1501 | 0 | result = sum(new_to_add); | 1502 | 0 | } | 1503 | 0 | if (fix_remainder_to_zero) { | 1504 | 0 | result.self_reduce(); | 1505 | 0 | result.assert_equal(zero()); | 1506 | 0 | } | 1507 | 0 | result.set_origin_tag(new_tag); | 1508 | 0 | return result; | 1509 | 0 | } | 1510 | 0 | } | 1511 | | | 1512 | | // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions, | 1513 | | // etc | 1514 | | | 1515 | | // Compute the constant term we're adding | 1516 | 1.29k | const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1517 | 1.29k | const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo; | 1518 | | | 1519 | 1.29k | if (constant_part_remainder_256 != uint256_t(0)) { | 1520 | 3 | new_to_add.push_back(bigfield(ctx, constant_part_remainder_256)); | 1521 | 3 | } | 1522 | | // Compute added sum | 1523 | 1.29k | uint1024_t add_right_final_sum(0); | 1524 | 1.29k | uint1024_t add_right_maximum(0); | 1525 | 1.37k | for (const auto& add_element : new_to_add) { | 1526 | | // Technically not needed, but better to leave just in case | 1527 | 1.37k | add_element.reduction_check(); | 1528 | 1.37k | add_right_final_sum += uint1024_t(add_element.get_value()); | 1529 | | | 1530 | 1.37k | add_right_maximum += uint1024_t(add_element.get_maximum_value()); | 1531 | 1.37k | } | 1532 | 1.29k | const size_t final_number_of_products = new_input_left.size(); | 1533 | | | 1534 | | // We need to check if it is possible to reduce the products enough | 1535 | 1.29k | worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) * | 1536 | 1.29k | uint1024_t(DEFAULT_MAXIMUM_REMAINDER); | 1537 | | | 1538 | | // Check that we can actually reduce the products enough, this assert will probably never get triggered | 1539 | 1.29k | ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product()); | 1540 | | | 1541 | | // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check | 1542 | | // if we need to reduce something | 1543 | 1.29k | perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add); | 1544 | 1.29k | uint1024_t sum_of_products_final(0); | 1545 | 4.44k | for (size_t i = 0; i < final_number_of_products; i++) { | 1546 | 3.15k | sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value()); | 1547 | 3.15k | } | 1548 | | | 1549 | | // Get the number of range proof bits for the quotient | 1550 | 1.29k | const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER }); | 1551 | | | 1552 | | // Compute the quotient and remainder | 1553 | 1.29k | const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus); | 1554 | | | 1555 | | // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is | 1556 | | | 1557 | 1.29k | if (fix_remainder_to_zero) { | 1558 | | // This is not the only check. Circuit check is coming later :) | 1559 | 1.09k | ASSERT(remainder_1024.lo == uint512_t(0)); | 1560 | 1.09k | } | 1561 | 1.29k | const uint512_t quotient_value = quotient_1024.lo; | 1562 | 1.29k | const uint512_t remainder_value = remainder_1024.lo; | 1563 | | | 1564 | 1.29k | bigfield remainder; | 1565 | 1.29k | bigfield quotient; | 1566 | | // Constrain quotient to mitigate CRT overflow attacks | 1567 | 1.29k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1568 | | | 1569 | 1.29k | if (fix_remainder_to_zero) { | 1570 | 1.09k | remainder = zero(); | 1571 | | // remainder needs to be defined as wire value and not selector values to satisfy | 1572 | | // Ultra's bigfield custom gates | 1573 | 1.09k | remainder.convert_constant_to_fixed_witness(ctx); | 1574 | 1.09k | } else { | 1575 | 192 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1576 | 192 | } | 1577 | | | 1578 | 1.29k | unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder }); | 1579 | | | 1580 | 1.29k | remainder.set_origin_tag(new_tag); | 1581 | 1.29k | return remainder; | 1582 | 1.29k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b Line | Count | Source | 1408 | 28.3k | { | 1409 | 28.3k | ASSERT(mul_left.size() == mul_right.size()); | 1410 | 28.3k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1411 | 28.3k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1412 | | | 1413 | 28.3k | std::vector<bigfield> mutable_mul_left(mul_left); | 1414 | 28.3k | std::vector<bigfield> mutable_mul_right(mul_right); | 1415 | | | 1416 | 28.3k | const size_t number_of_products = mul_left.size(); | 1417 | | | 1418 | 28.3k | const uint1024_t modulus(target_basis.modulus); | 1419 | 28.3k | uint1024_t worst_case_product_sum(0); | 1420 | 28.3k | uint1024_t add_right_constant_sum(0); | 1421 | | | 1422 | | // First we do all constant optimizations | 1423 | 28.3k | bool add_constant = true; | 1424 | 28.3k | std::vector<bigfield> new_to_add; | 1425 | | | 1426 | 28.3k | OriginTag new_tag{}; | 1427 | | // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge) | 1428 | 70.5k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1429 | 70.5k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1430 | 70.5k | } | 1431 | 33.1k | for (auto& element : to_add) { | 1432 | 33.1k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1433 | 33.1k | } | 1434 | | | 1435 | 33.1k | for (const auto& add_element : to_add) { | 1436 | 33.1k | add_element.reduction_check(); | 1437 | 33.1k | if (add_element.is_constant()) { | 1438 | 0 | add_right_constant_sum += uint1024_t(add_element.get_value()); | 1439 | 33.1k | } else { | 1440 | 33.1k | add_constant = false; | 1441 | 33.1k | new_to_add.push_back(add_element); | 1442 | 33.1k | } | 1443 | 33.1k | } | 1444 | | | 1445 | | // Compute the product sum | 1446 | | // Optimize constant use | 1447 | 28.3k | uint1024_t sum_of_constant_products(0); | 1448 | 28.3k | std::vector<bigfield> new_input_left; | 1449 | 28.3k | std::vector<bigfield> new_input_right; | 1450 | 28.3k | bool product_sum_constant = true; | 1451 | 98.9k | for (size_t i = 0; i < number_of_products; i++) { | 1452 | 70.5k | if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) { | 1453 | | // If constant, just add to the sum | 1454 | 0 | sum_of_constant_products += | 1455 | 0 | uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value()); | 1456 | 70.5k | } else { | 1457 | | // If not, add to nonconstant sum and remember the elements | 1458 | 70.5k | new_input_left.push_back(mutable_mul_left[i]); | 1459 | 70.5k | new_input_right.push_back(mutable_mul_right[i]); | 1460 | 70.5k | product_sum_constant = false; | 1461 | 70.5k | } | 1462 | 70.5k | } | 1463 | | | 1464 | 28.3k | Builder* ctx = nullptr; | 1465 | | // Search through all multiplicands on the left | 1466 | 28.3k | for (auto& el : mutable_mul_left) { | 1467 | 28.3k | if (el.context) { | 1468 | 28.3k | ctx = el.context; | 1469 | 28.3k | break; | 1470 | 28.3k | } | 1471 | 28.3k | } | 1472 | | // And on the right | 1473 | 28.3k | if (!ctx) { | 1474 | 0 | for (auto& el : mutable_mul_right) { | 1475 | 0 | if (el.context) { | 1476 | 0 | ctx = el.context; | 1477 | 0 | break; | 1478 | 0 | } | 1479 | 0 | } | 1480 | 0 | } | 1481 | 28.3k | if (product_sum_constant) { | 1482 | 0 | if (add_constant) { | 1483 | | // Simply return the constant, no need unsafe_multiply_add | 1484 | 0 | const auto [quotient_1024, remainder_1024] = | 1485 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1486 | 0 | ASSERT(!fix_remainder_to_zero || remainder_1024 == 0); | 1487 | 0 | auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1488 | 0 | result.set_origin_tag(new_tag); | 1489 | 0 | return result; | 1490 | 0 | } else { | 1491 | 0 | const auto [quotient_1024, remainder_1024] = | 1492 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1493 | 0 | uint256_t remainder_value = remainder_1024.lo.lo; | 1494 | 0 | bigfield result; | 1495 | 0 | if (remainder_value == uint256_t(0)) { | 1496 | | // No need to add extra term to new_to_add | 1497 | 0 | result = sum(new_to_add); | 1498 | 0 | } else { | 1499 | | // Add the constant term | 1500 | 0 | new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value))); | 1501 | 0 | result = sum(new_to_add); | 1502 | 0 | } | 1503 | 0 | if (fix_remainder_to_zero) { | 1504 | 0 | result.self_reduce(); | 1505 | 0 | result.assert_equal(zero()); | 1506 | 0 | } | 1507 | 0 | result.set_origin_tag(new_tag); | 1508 | 0 | return result; | 1509 | 0 | } | 1510 | 0 | } | 1511 | | | 1512 | | // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions, | 1513 | | // etc | 1514 | | | 1515 | | // Compute the constant term we're adding | 1516 | 28.3k | const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1517 | 28.3k | const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo; | 1518 | | | 1519 | 28.3k | if (constant_part_remainder_256 != uint256_t(0)) { | 1520 | 0 | new_to_add.push_back(bigfield(ctx, constant_part_remainder_256)); | 1521 | 0 | } | 1522 | | // Compute added sum | 1523 | 28.3k | uint1024_t add_right_final_sum(0); | 1524 | 28.3k | uint1024_t add_right_maximum(0); | 1525 | 33.1k | for (const auto& add_element : new_to_add) { | 1526 | | // Technically not needed, but better to leave just in case | 1527 | 33.1k | add_element.reduction_check(); | 1528 | 33.1k | add_right_final_sum += uint1024_t(add_element.get_value()); | 1529 | | | 1530 | 33.1k | add_right_maximum += uint1024_t(add_element.get_maximum_value()); | 1531 | 33.1k | } | 1532 | 28.3k | const size_t final_number_of_products = new_input_left.size(); | 1533 | | | 1534 | | // We need to check if it is possible to reduce the products enough | 1535 | 28.3k | worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) * | 1536 | 28.3k | uint1024_t(DEFAULT_MAXIMUM_REMAINDER); | 1537 | | | 1538 | | // Check that we can actually reduce the products enough, this assert will probably never get triggered | 1539 | 28.3k | ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product()); | 1540 | | | 1541 | | // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check | 1542 | | // if we need to reduce something | 1543 | 28.3k | perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add); | 1544 | 28.3k | uint1024_t sum_of_products_final(0); | 1545 | 98.9k | for (size_t i = 0; i < final_number_of_products; i++) { | 1546 | 70.5k | sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value()); | 1547 | 70.5k | } | 1548 | | | 1549 | | // Get the number of range proof bits for the quotient | 1550 | 28.3k | const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER }); | 1551 | | | 1552 | | // Compute the quotient and remainder | 1553 | 28.3k | const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus); | 1554 | | | 1555 | | // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is | 1556 | | | 1557 | 28.3k | if (fix_remainder_to_zero) { | 1558 | | // This is not the only check. Circuit check is coming later :) | 1559 | 23.7k | ASSERT(remainder_1024.lo == uint512_t(0)); | 1560 | 23.7k | } | 1561 | 28.3k | const uint512_t quotient_value = quotient_1024.lo; | 1562 | 28.3k | const uint512_t remainder_value = remainder_1024.lo; | 1563 | | | 1564 | 28.3k | bigfield remainder; | 1565 | 28.3k | bigfield quotient; | 1566 | | // Constrain quotient to mitigate CRT overflow attacks | 1567 | 28.3k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1568 | | | 1569 | 28.3k | if (fix_remainder_to_zero) { | 1570 | 23.7k | remainder = zero(); | 1571 | | // remainder needs to be defined as wire value and not selector values to satisfy | 1572 | | // Ultra's bigfield custom gates | 1573 | 23.7k | remainder.convert_constant_to_fixed_witness(ctx); | 1574 | 23.7k | } else { | 1575 | 4.60k | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1576 | 4.60k | } | 1577 | | | 1578 | 28.3k | unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder }); | 1579 | | | 1580 | 28.3k | remainder.set_origin_tag(new_tag); | 1581 | 28.3k | return remainder; | 1582 | 28.3k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b Line | Count | Source | 1408 | 2.23k | { | 1409 | 2.23k | ASSERT(mul_left.size() == mul_right.size()); | 1410 | 2.23k | ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT); | 1411 | 2.23k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1412 | | | 1413 | 2.23k | std::vector<bigfield> mutable_mul_left(mul_left); | 1414 | 2.23k | std::vector<bigfield> mutable_mul_right(mul_right); | 1415 | | | 1416 | 2.23k | const size_t number_of_products = mul_left.size(); | 1417 | | | 1418 | 2.23k | const uint1024_t modulus(target_basis.modulus); | 1419 | 2.23k | uint1024_t worst_case_product_sum(0); | 1420 | 2.23k | uint1024_t add_right_constant_sum(0); | 1421 | | | 1422 | | // First we do all constant optimizations | 1423 | 2.23k | bool add_constant = true; | 1424 | 2.23k | std::vector<bigfield> new_to_add; | 1425 | | | 1426 | 2.23k | OriginTag new_tag{}; | 1427 | | // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge) | 1428 | 7.01k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1429 | 7.01k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1430 | 7.01k | } | 1431 | 3.19k | for (auto& element : to_add) { | 1432 | 3.19k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1433 | 3.19k | } | 1434 | | | 1435 | 3.19k | for (const auto& add_element : to_add) { | 1436 | 3.19k | add_element.reduction_check(); | 1437 | 3.19k | if (add_element.is_constant()) { | 1438 | 4 | add_right_constant_sum += uint1024_t(add_element.get_value()); | 1439 | 3.18k | } else { | 1440 | 3.18k | add_constant = false; | 1441 | 3.18k | new_to_add.push_back(add_element); | 1442 | 3.18k | } | 1443 | 3.19k | } | 1444 | | | 1445 | | // Compute the product sum | 1446 | | // Optimize constant use | 1447 | 2.23k | uint1024_t sum_of_constant_products(0); | 1448 | 2.23k | std::vector<bigfield> new_input_left; | 1449 | 2.23k | std::vector<bigfield> new_input_right; | 1450 | 2.23k | bool product_sum_constant = true; | 1451 | 9.24k | for (size_t i = 0; i < number_of_products; i++) { | 1452 | 7.01k | if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) { | 1453 | | // If constant, just add to the sum | 1454 | 0 | sum_of_constant_products += | 1455 | 0 | uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value()); | 1456 | 7.01k | } else { | 1457 | | // If not, add to nonconstant sum and remember the elements | 1458 | 7.01k | new_input_left.push_back(mutable_mul_left[i]); | 1459 | 7.01k | new_input_right.push_back(mutable_mul_right[i]); | 1460 | 7.01k | product_sum_constant = false; | 1461 | 7.01k | } | 1462 | 7.01k | } | 1463 | | | 1464 | 2.23k | Builder* ctx = nullptr; | 1465 | | // Search through all multiplicands on the left | 1466 | 2.23k | for (auto& el : mutable_mul_left) { | 1467 | 2.23k | if (el.context) { | 1468 | 2.23k | ctx = el.context; | 1469 | 2.23k | break; | 1470 | 2.23k | } | 1471 | 2.23k | } | 1472 | | // And on the right | 1473 | 2.23k | if (!ctx) { | 1474 | 0 | for (auto& el : mutable_mul_right) { | 1475 | 0 | if (el.context) { | 1476 | 0 | ctx = el.context; | 1477 | 0 | break; | 1478 | 0 | } | 1479 | 0 | } | 1480 | 0 | } | 1481 | 2.23k | if (product_sum_constant) { | 1482 | 0 | if (add_constant) { | 1483 | | // Simply return the constant, no need unsafe_multiply_add | 1484 | 0 | const auto [quotient_1024, remainder_1024] = | 1485 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1486 | 0 | ASSERT(!fix_remainder_to_zero || remainder_1024 == 0); | 1487 | 0 | auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo)); | 1488 | 0 | result.set_origin_tag(new_tag); | 1489 | 0 | return result; | 1490 | 0 | } else { | 1491 | 0 | const auto [quotient_1024, remainder_1024] = | 1492 | 0 | (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1493 | 0 | uint256_t remainder_value = remainder_1024.lo.lo; | 1494 | 0 | bigfield result; | 1495 | 0 | if (remainder_value == uint256_t(0)) { | 1496 | | // No need to add extra term to new_to_add | 1497 | 0 | result = sum(new_to_add); | 1498 | 0 | } else { | 1499 | | // Add the constant term | 1500 | 0 | new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value))); | 1501 | 0 | result = sum(new_to_add); | 1502 | 0 | } | 1503 | 0 | if (fix_remainder_to_zero) { | 1504 | 0 | result.self_reduce(); | 1505 | 0 | result.assert_equal(zero()); | 1506 | 0 | } | 1507 | 0 | result.set_origin_tag(new_tag); | 1508 | 0 | return result; | 1509 | 0 | } | 1510 | 0 | } | 1511 | | | 1512 | | // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions, | 1513 | | // etc | 1514 | | | 1515 | | // Compute the constant term we're adding | 1516 | 2.23k | const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus); | 1517 | 2.23k | const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo; | 1518 | | | 1519 | 2.23k | if (constant_part_remainder_256 != uint256_t(0)) { | 1520 | 4 | new_to_add.push_back(bigfield(ctx, constant_part_remainder_256)); | 1521 | 4 | } | 1522 | | // Compute added sum | 1523 | 2.23k | uint1024_t add_right_final_sum(0); | 1524 | 2.23k | uint1024_t add_right_maximum(0); | 1525 | 3.19k | for (const auto& add_element : new_to_add) { | 1526 | | // Technically not needed, but better to leave just in case | 1527 | 3.19k | add_element.reduction_check(); | 1528 | 3.19k | add_right_final_sum += uint1024_t(add_element.get_value()); | 1529 | | | 1530 | 3.19k | add_right_maximum += uint1024_t(add_element.get_maximum_value()); | 1531 | 3.19k | } | 1532 | 2.23k | const size_t final_number_of_products = new_input_left.size(); | 1533 | | | 1534 | | // We need to check if it is possible to reduce the products enough | 1535 | 2.23k | worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) * | 1536 | 2.23k | uint1024_t(DEFAULT_MAXIMUM_REMAINDER); | 1537 | | | 1538 | | // Check that we can actually reduce the products enough, this assert will probably never get triggered | 1539 | 2.23k | ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product()); | 1540 | | | 1541 | | // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check | 1542 | | // if we need to reduce something | 1543 | 2.23k | perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add); | 1544 | 2.23k | uint1024_t sum_of_products_final(0); | 1545 | 9.24k | for (size_t i = 0; i < final_number_of_products; i++) { | 1546 | 7.01k | sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value()); | 1547 | 7.01k | } | 1548 | | | 1549 | | // Get the number of range proof bits for the quotient | 1550 | 2.23k | const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER }); | 1551 | | | 1552 | | // Compute the quotient and remainder | 1553 | 2.23k | const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus); | 1554 | | | 1555 | | // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is | 1556 | | | 1557 | 2.23k | if (fix_remainder_to_zero) { | 1558 | | // This is not the only check. Circuit check is coming later :) | 1559 | 1.91k | ASSERT(remainder_1024.lo == uint512_t(0)); | 1560 | 1.91k | } | 1561 | 2.23k | const uint512_t quotient_value = quotient_1024.lo; | 1562 | 2.23k | const uint512_t remainder_value = remainder_1024.lo; | 1563 | | | 1564 | 2.23k | bigfield remainder; | 1565 | 2.23k | bigfield quotient; | 1566 | | // Constrain quotient to mitigate CRT overflow attacks | 1567 | 2.23k | quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits); | 1568 | | | 1569 | 2.23k | if (fix_remainder_to_zero) { | 1570 | 1.91k | remainder = zero(); | 1571 | | // remainder needs to be defined as wire value and not selector values to satisfy | 1572 | | // Ultra's bigfield custom gates | 1573 | 1.91k | remainder.convert_constant_to_fixed_witness(ctx); | 1574 | 1.91k | } else { | 1575 | 320 | remainder = create_from_u512_as_witness(ctx, remainder_value); | 1576 | 320 | } | 1577 | | | 1578 | 2.23k | unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder }); | 1579 | | | 1580 | 2.23k | remainder.set_origin_tag(new_tag); | 1581 | 2.23k | return remainder; | 1582 | 2.23k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b |
1583 | | |
1584 | | /** |
1585 | | * Compute (left_a * right_a) + (left_b * right_b) + ...to_add = c mod p |
1586 | | * |
1587 | | * This is cheaper than two multiplication operations, as the above only requires one quotient/remainder |
1588 | | **/ |
1589 | | template <typename Builder, typename T> |
1590 | | bigfield<Builder, T> bigfield<Builder, T>::dual_madd(const bigfield& left_a, |
1591 | | const bigfield& right_a, |
1592 | | const bigfield& left_b, |
1593 | | const bigfield& right_b, |
1594 | | const std::vector<bigfield>& to_add) |
1595 | 1 | { |
1596 | 1 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
1597 | 0 | left_a.reduction_check(); |
1598 | 0 | right_a.reduction_check(); |
1599 | 0 | left_b.reduction_check(); |
1600 | 0 | right_b.reduction_check(); |
1601 | |
|
1602 | 0 | std::vector<bigfield> mul_left = { left_a, left_b }; |
1603 | 0 | std::vector<bigfield> mul_right = { right_a, right_b }; |
1604 | |
|
1605 | 0 | return mult_madd(mul_left, mul_right, to_add); |
1606 | 1 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE Line | Count | Source | 1595 | 1 | { | 1596 | 1 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 1597 | 1 | left_a.reduction_check(); | 1598 | 1 | right_a.reduction_check(); | 1599 | 1 | left_b.reduction_check(); | 1600 | 1 | right_b.reduction_check(); | 1601 | | | 1602 | 1 | std::vector<bigfield> mul_left = { left_a, left_b }; | 1603 | 1 | std::vector<bigfield> mul_right = { right_a, right_b }; | 1604 | | | 1605 | 1 | return mult_madd(mul_left, mul_right, to_add); | 1606 | 1 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE |
1607 | | |
1608 | | /** |
1609 | | * multiply, subtract, divide. |
1610 | | * This method computes: |
1611 | | * |
1612 | | * result = -(\sum{mul_left[i] * mul_right[i]} + ...to_add) / divisor |
1613 | | * |
1614 | | * Algorithm is constructed in this way to ensure that all computed terms are positive |
1615 | | * |
1616 | | * i.e. we evaluate: |
1617 | | * result * divisor + (\sum{mul_left[i] * mul_right[i]) + ...to_add) = 0 |
1618 | | * |
1619 | | * It is critical that ALL the terms on the LHS are positive to eliminate the possiblity of underflows |
1620 | | * when calling `evaluate_multiple_multiply_add` |
1621 | | * |
1622 | | * only requires one quotient and remainder + overflow limbs |
1623 | | * |
1624 | | * We proxy this to mult_madd, so it only requires one quotient and remainder + overflow limbs |
1625 | | **/ |
1626 | | template <typename Builder, typename T> |
1627 | | bigfield<Builder, T> bigfield<Builder, T>::msub_div(const std::vector<bigfield>& mul_left, |
1628 | | const std::vector<bigfield>& mul_right, |
1629 | | const bigfield& divisor, |
1630 | | const std::vector<bigfield>& to_sub, |
1631 | | bool enable_divisor_nz_check) |
1632 | 340k | { |
1633 | | // Check the basics |
1634 | 340k | ASSERT(mul_left.size() == mul_right.size()); |
1635 | 340k | ASSERT(divisor.get_value() != 0); |
1636 | | |
1637 | 0 | OriginTag new_tag = divisor.get_origin_tag(); |
1638 | 405k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { |
1639 | 405k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); |
1640 | 405k | } |
1641 | 623k | for (auto& element : to_sub) { |
1642 | 623k | new_tag = OriginTag(new_tag, element.get_origin_tag()); |
1643 | 623k | } |
1644 | | // Gett he context |
1645 | 0 | Builder* ctx = divisor.context; |
1646 | 340k | if (ctx == NULL) { |
1647 | 1 | for (auto& el : mul_left) { |
1648 | 1 | if (el.context != NULL) { |
1649 | 1 | ctx = el.context; |
1650 | 1 | break; |
1651 | 1 | } |
1652 | 1 | } |
1653 | 1 | } |
1654 | 340k | if (ctx == NULL) { |
1655 | 0 | for (auto& el : mul_right) { |
1656 | 0 | if (el.context != NULL) { |
1657 | 0 | ctx = el.context; |
1658 | 0 | break; |
1659 | 0 | } |
1660 | 0 | } |
1661 | 0 | } |
1662 | 340k | if (ctx == NULL) { |
1663 | 0 | for (auto& el : to_sub) { |
1664 | 0 | if (el.context != NULL) { |
1665 | 0 | ctx = el.context; |
1666 | 0 | break; |
1667 | 0 | } |
1668 | 0 | } |
1669 | 0 | } |
1670 | 0 | const size_t num_multiplications = mul_left.size(); |
1671 | 0 | native product_native = 0; |
1672 | 0 | bool products_constant = true; |
1673 | | |
1674 | | // This check is optional, because it is heavy and often we don't need it at all |
1675 | 340k | if (enable_divisor_nz_check) { |
1676 | 1 | divisor.assert_is_not_equal(zero()); |
1677 | 1 | } |
1678 | | |
1679 | | // Compute the sum of products |
1680 | 745k | for (size_t i = 0; i < num_multiplications; ++i) { |
1681 | 405k | const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo); |
1682 | 405k | const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo); |
1683 | 405k | product_native += (mul_left_native * -mul_right_native); |
1684 | 405k | products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant(); |
1685 | 405k | } |
1686 | | |
1687 | | // Compute the sum of to_sub |
1688 | 0 | native sub_native(0); |
1689 | 0 | bool sub_constant = true; |
1690 | 623k | for (const auto& sub : to_sub) { |
1691 | 623k | sub_native += (uint512_t(sub.get_value() % modulus_u512).lo); |
1692 | 623k | sub_constant = sub_constant && sub.is_constant(); |
1693 | 623k | } |
1694 | |
|
1695 | 0 | native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo); |
1696 | | |
1697 | | // Compute the result |
1698 | 0 | const native result_native = (product_native - sub_native) / divisor_native; |
1699 | |
|
1700 | 0 | const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native))); |
1701 | | |
1702 | | // If everything is constant, then we just return the constant |
1703 | 340k | if (sub_constant && products_constant && divisor.is_constant()) { |
1704 | 0 | auto result = bigfield(ctx, uint256_t(result_value.lo.lo)); |
1705 | 0 | result.set_origin_tag(new_tag); |
1706 | 0 | return result; |
1707 | 0 | } |
1708 | | |
1709 | 340k | ASSERT(ctx != NULL); |
1710 | | // Create the result witness |
1711 | 0 | bigfield result = create_from_u512_as_witness(ctx, result_value.lo); |
1712 | |
|
1713 | 0 | std::vector<bigfield> eval_left{ result }; |
1714 | 0 | std::vector<bigfield> eval_right{ divisor }; |
1715 | 405k | for (const auto& in : mul_left) { |
1716 | 405k | eval_left.emplace_back(in); |
1717 | 405k | } |
1718 | 405k | for (const auto& in : mul_right) { |
1719 | 405k | eval_right.emplace_back(in); |
1720 | 405k | } |
1721 | |
|
1722 | 0 | mult_madd(eval_left, eval_right, to_sub, true); |
1723 | |
|
1724 | 0 | result.set_origin_tag(new_tag); |
1725 | 0 | return result; |
1726 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b Line | Count | Source | 1632 | 313k | { | 1633 | | // Check the basics | 1634 | 313k | ASSERT(mul_left.size() == mul_right.size()); | 1635 | 313k | ASSERT(divisor.get_value() != 0); | 1636 | | | 1637 | 313k | OriginTag new_tag = divisor.get_origin_tag(); | 1638 | 367k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1639 | 367k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1640 | 367k | } | 1641 | 590k | for (auto& element : to_sub) { | 1642 | 590k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1643 | 590k | } | 1644 | | // Gett he context | 1645 | 313k | Builder* ctx = divisor.context; | 1646 | 313k | if (ctx == NULL) { | 1647 | 1 | for (auto& el : mul_left) { | 1648 | 1 | if (el.context != NULL) { | 1649 | 1 | ctx = el.context; | 1650 | 1 | break; | 1651 | 1 | } | 1652 | 1 | } | 1653 | 1 | } | 1654 | 313k | if (ctx == NULL) { | 1655 | 0 | for (auto& el : mul_right) { | 1656 | 0 | if (el.context != NULL) { | 1657 | 0 | ctx = el.context; | 1658 | 0 | break; | 1659 | 0 | } | 1660 | 0 | } | 1661 | 0 | } | 1662 | 313k | if (ctx == NULL) { | 1663 | 0 | for (auto& el : to_sub) { | 1664 | 0 | if (el.context != NULL) { | 1665 | 0 | ctx = el.context; | 1666 | 0 | break; | 1667 | 0 | } | 1668 | 0 | } | 1669 | 0 | } | 1670 | 313k | const size_t num_multiplications = mul_left.size(); | 1671 | 313k | native product_native = 0; | 1672 | 313k | bool products_constant = true; | 1673 | | | 1674 | | // This check is optional, because it is heavy and often we don't need it at all | 1675 | 313k | if (enable_divisor_nz_check) { | 1676 | 1 | divisor.assert_is_not_equal(zero()); | 1677 | 1 | } | 1678 | | | 1679 | | // Compute the sum of products | 1680 | 681k | for (size_t i = 0; i < num_multiplications; ++i) { | 1681 | 367k | const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo); | 1682 | 367k | const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo); | 1683 | 367k | product_native += (mul_left_native * -mul_right_native); | 1684 | 367k | products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant(); | 1685 | 367k | } | 1686 | | | 1687 | | // Compute the sum of to_sub | 1688 | 313k | native sub_native(0); | 1689 | 313k | bool sub_constant = true; | 1690 | 590k | for (const auto& sub : to_sub) { | 1691 | 590k | sub_native += (uint512_t(sub.get_value() % modulus_u512).lo); | 1692 | 590k | sub_constant = sub_constant && sub.is_constant(); | 1693 | 590k | } | 1694 | | | 1695 | 313k | native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo); | 1696 | | | 1697 | | // Compute the result | 1698 | 313k | const native result_native = (product_native - sub_native) / divisor_native; | 1699 | | | 1700 | 313k | const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native))); | 1701 | | | 1702 | | // If everything is constant, then we just return the constant | 1703 | 313k | if (sub_constant && products_constant && divisor.is_constant()) { | 1704 | 0 | auto result = bigfield(ctx, uint256_t(result_value.lo.lo)); | 1705 | 0 | result.set_origin_tag(new_tag); | 1706 | 0 | return result; | 1707 | 0 | } | 1708 | | | 1709 | 313k | ASSERT(ctx != NULL); | 1710 | | // Create the result witness | 1711 | 313k | bigfield result = create_from_u512_as_witness(ctx, result_value.lo); | 1712 | | | 1713 | 313k | std::vector<bigfield> eval_left{ result }; | 1714 | 313k | std::vector<bigfield> eval_right{ divisor }; | 1715 | 367k | for (const auto& in : mul_left) { | 1716 | 367k | eval_left.emplace_back(in); | 1717 | 367k | } | 1718 | 367k | for (const auto& in : mul_right) { | 1719 | 367k | eval_right.emplace_back(in); | 1720 | 367k | } | 1721 | | | 1722 | 313k | mult_madd(eval_left, eval_right, to_sub, true); | 1723 | | | 1724 | 313k | result.set_origin_tag(new_tag); | 1725 | 313k | return result; | 1726 | 313k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b Line | Count | Source | 1632 | 1.09k | { | 1633 | | // Check the basics | 1634 | 1.09k | ASSERT(mul_left.size() == mul_right.size()); | 1635 | 1.09k | ASSERT(divisor.get_value() != 0); | 1636 | | | 1637 | 1.09k | OriginTag new_tag = divisor.get_origin_tag(); | 1638 | 1.47k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1639 | 1.47k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1640 | 1.47k | } | 1641 | 1.17k | for (auto& element : to_sub) { | 1642 | 1.17k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1643 | 1.17k | } | 1644 | | // Gett he context | 1645 | 1.09k | Builder* ctx = divisor.context; | 1646 | 1.09k | if (ctx == NULL) { | 1647 | 0 | for (auto& el : mul_left) { | 1648 | 0 | if (el.context != NULL) { | 1649 | 0 | ctx = el.context; | 1650 | 0 | break; | 1651 | 0 | } | 1652 | 0 | } | 1653 | 0 | } | 1654 | 1.09k | if (ctx == NULL) { | 1655 | 0 | for (auto& el : mul_right) { | 1656 | 0 | if (el.context != NULL) { | 1657 | 0 | ctx = el.context; | 1658 | 0 | break; | 1659 | 0 | } | 1660 | 0 | } | 1661 | 0 | } | 1662 | 1.09k | if (ctx == NULL) { | 1663 | 0 | for (auto& el : to_sub) { | 1664 | 0 | if (el.context != NULL) { | 1665 | 0 | ctx = el.context; | 1666 | 0 | break; | 1667 | 0 | } | 1668 | 0 | } | 1669 | 0 | } | 1670 | 1.09k | const size_t num_multiplications = mul_left.size(); | 1671 | 1.09k | native product_native = 0; | 1672 | 1.09k | bool products_constant = true; | 1673 | | | 1674 | | // This check is optional, because it is heavy and often we don't need it at all | 1675 | 1.09k | if (enable_divisor_nz_check) { | 1676 | 0 | divisor.assert_is_not_equal(zero()); | 1677 | 0 | } | 1678 | | | 1679 | | // Compute the sum of products | 1680 | 2.56k | for (size_t i = 0; i < num_multiplications; ++i) { | 1681 | 1.47k | const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo); | 1682 | 1.47k | const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo); | 1683 | 1.47k | product_native += (mul_left_native * -mul_right_native); | 1684 | 1.47k | products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant(); | 1685 | 1.47k | } | 1686 | | | 1687 | | // Compute the sum of to_sub | 1688 | 1.09k | native sub_native(0); | 1689 | 1.09k | bool sub_constant = true; | 1690 | 1.17k | for (const auto& sub : to_sub) { | 1691 | 1.17k | sub_native += (uint512_t(sub.get_value() % modulus_u512).lo); | 1692 | 1.17k | sub_constant = sub_constant && sub.is_constant(); | 1693 | 1.17k | } | 1694 | | | 1695 | 1.09k | native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo); | 1696 | | | 1697 | | // Compute the result | 1698 | 1.09k | const native result_native = (product_native - sub_native) / divisor_native; | 1699 | | | 1700 | 1.09k | const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native))); | 1701 | | | 1702 | | // If everything is constant, then we just return the constant | 1703 | 1.09k | if (sub_constant && products_constant && divisor.is_constant()) { | 1704 | 0 | auto result = bigfield(ctx, uint256_t(result_value.lo.lo)); | 1705 | 0 | result.set_origin_tag(new_tag); | 1706 | 0 | return result; | 1707 | 0 | } | 1708 | | | 1709 | 1.09k | ASSERT(ctx != NULL); | 1710 | | // Create the result witness | 1711 | 1.09k | bigfield result = create_from_u512_as_witness(ctx, result_value.lo); | 1712 | | | 1713 | 1.09k | std::vector<bigfield> eval_left{ result }; | 1714 | 1.09k | std::vector<bigfield> eval_right{ divisor }; | 1715 | 1.47k | for (const auto& in : mul_left) { | 1716 | 1.47k | eval_left.emplace_back(in); | 1717 | 1.47k | } | 1718 | 1.47k | for (const auto& in : mul_right) { | 1719 | 1.47k | eval_right.emplace_back(in); | 1720 | 1.47k | } | 1721 | | | 1722 | 1.09k | mult_madd(eval_left, eval_right, to_sub, true); | 1723 | | | 1724 | 1.09k | result.set_origin_tag(new_tag); | 1725 | 1.09k | return result; | 1726 | 1.09k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b Line | Count | Source | 1632 | 23.4k | { | 1633 | | // Check the basics | 1634 | 23.4k | ASSERT(mul_left.size() == mul_right.size()); | 1635 | 23.4k | ASSERT(divisor.get_value() != 0); | 1636 | | | 1637 | 23.4k | OriginTag new_tag = divisor.get_origin_tag(); | 1638 | 32.6k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1639 | 32.6k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1640 | 32.6k | } | 1641 | 28.2k | for (auto& element : to_sub) { | 1642 | 28.2k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1643 | 28.2k | } | 1644 | | // Gett he context | 1645 | 23.4k | Builder* ctx = divisor.context; | 1646 | 23.4k | if (ctx == NULL) { | 1647 | 0 | for (auto& el : mul_left) { | 1648 | 0 | if (el.context != NULL) { | 1649 | 0 | ctx = el.context; | 1650 | 0 | break; | 1651 | 0 | } | 1652 | 0 | } | 1653 | 0 | } | 1654 | 23.4k | if (ctx == NULL) { | 1655 | 0 | for (auto& el : mul_right) { | 1656 | 0 | if (el.context != NULL) { | 1657 | 0 | ctx = el.context; | 1658 | 0 | break; | 1659 | 0 | } | 1660 | 0 | } | 1661 | 0 | } | 1662 | 23.4k | if (ctx == NULL) { | 1663 | 0 | for (auto& el : to_sub) { | 1664 | 0 | if (el.context != NULL) { | 1665 | 0 | ctx = el.context; | 1666 | 0 | break; | 1667 | 0 | } | 1668 | 0 | } | 1669 | 0 | } | 1670 | 23.4k | const size_t num_multiplications = mul_left.size(); | 1671 | 23.4k | native product_native = 0; | 1672 | 23.4k | bool products_constant = true; | 1673 | | | 1674 | | // This check is optional, because it is heavy and often we don't need it at all | 1675 | 23.4k | if (enable_divisor_nz_check) { | 1676 | 0 | divisor.assert_is_not_equal(zero()); | 1677 | 0 | } | 1678 | | | 1679 | | // Compute the sum of products | 1680 | 56.1k | for (size_t i = 0; i < num_multiplications; ++i) { | 1681 | 32.6k | const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo); | 1682 | 32.6k | const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo); | 1683 | 32.6k | product_native += (mul_left_native * -mul_right_native); | 1684 | 32.6k | products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant(); | 1685 | 32.6k | } | 1686 | | | 1687 | | // Compute the sum of to_sub | 1688 | 23.4k | native sub_native(0); | 1689 | 23.4k | bool sub_constant = true; | 1690 | 28.2k | for (const auto& sub : to_sub) { | 1691 | 28.2k | sub_native += (uint512_t(sub.get_value() % modulus_u512).lo); | 1692 | 28.2k | sub_constant = sub_constant && sub.is_constant(); | 1693 | 28.2k | } | 1694 | | | 1695 | 23.4k | native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo); | 1696 | | | 1697 | | // Compute the result | 1698 | 23.4k | const native result_native = (product_native - sub_native) / divisor_native; | 1699 | | | 1700 | 23.4k | const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native))); | 1701 | | | 1702 | | // If everything is constant, then we just return the constant | 1703 | 23.4k | if (sub_constant && products_constant && divisor.is_constant()) { | 1704 | 0 | auto result = bigfield(ctx, uint256_t(result_value.lo.lo)); | 1705 | 0 | result.set_origin_tag(new_tag); | 1706 | 0 | return result; | 1707 | 0 | } | 1708 | | | 1709 | 23.4k | ASSERT(ctx != NULL); | 1710 | | // Create the result witness | 1711 | 23.4k | bigfield result = create_from_u512_as_witness(ctx, result_value.lo); | 1712 | | | 1713 | 23.4k | std::vector<bigfield> eval_left{ result }; | 1714 | 23.4k | std::vector<bigfield> eval_right{ divisor }; | 1715 | 32.6k | for (const auto& in : mul_left) { | 1716 | 32.6k | eval_left.emplace_back(in); | 1717 | 32.6k | } | 1718 | 32.6k | for (const auto& in : mul_right) { | 1719 | 32.6k | eval_right.emplace_back(in); | 1720 | 32.6k | } | 1721 | | | 1722 | 23.4k | mult_madd(eval_left, eval_right, to_sub, true); | 1723 | | | 1724 | 23.4k | result.set_origin_tag(new_tag); | 1725 | 23.4k | return result; | 1726 | 23.4k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b Line | Count | Source | 1632 | 1.91k | { | 1633 | | // Check the basics | 1634 | 1.91k | ASSERT(mul_left.size() == mul_right.size()); | 1635 | 1.91k | ASSERT(divisor.get_value() != 0); | 1636 | | | 1637 | 1.91k | OriginTag new_tag = divisor.get_origin_tag(); | 1638 | 3.81k | for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) { | 1639 | 3.81k | new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag())); | 1640 | 3.81k | } | 1641 | 2.86k | for (auto& element : to_sub) { | 1642 | 2.86k | new_tag = OriginTag(new_tag, element.get_origin_tag()); | 1643 | 2.86k | } | 1644 | | // Gett he context | 1645 | 1.91k | Builder* ctx = divisor.context; | 1646 | 1.91k | if (ctx == NULL) { | 1647 | 0 | for (auto& el : mul_left) { | 1648 | 0 | if (el.context != NULL) { | 1649 | 0 | ctx = el.context; | 1650 | 0 | break; | 1651 | 0 | } | 1652 | 0 | } | 1653 | 0 | } | 1654 | 1.91k | if (ctx == NULL) { | 1655 | 0 | for (auto& el : mul_right) { | 1656 | 0 | if (el.context != NULL) { | 1657 | 0 | ctx = el.context; | 1658 | 0 | break; | 1659 | 0 | } | 1660 | 0 | } | 1661 | 0 | } | 1662 | 1.91k | if (ctx == NULL) { | 1663 | 0 | for (auto& el : to_sub) { | 1664 | 0 | if (el.context != NULL) { | 1665 | 0 | ctx = el.context; | 1666 | 0 | break; | 1667 | 0 | } | 1668 | 0 | } | 1669 | 0 | } | 1670 | 1.91k | const size_t num_multiplications = mul_left.size(); | 1671 | 1.91k | native product_native = 0; | 1672 | 1.91k | bool products_constant = true; | 1673 | | | 1674 | | // This check is optional, because it is heavy and often we don't need it at all | 1675 | 1.91k | if (enable_divisor_nz_check) { | 1676 | 0 | divisor.assert_is_not_equal(zero()); | 1677 | 0 | } | 1678 | | | 1679 | | // Compute the sum of products | 1680 | 5.72k | for (size_t i = 0; i < num_multiplications; ++i) { | 1681 | 3.81k | const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo); | 1682 | 3.81k | const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo); | 1683 | 3.81k | product_native += (mul_left_native * -mul_right_native); | 1684 | 3.81k | products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant(); | 1685 | 3.81k | } | 1686 | | | 1687 | | // Compute the sum of to_sub | 1688 | 1.91k | native sub_native(0); | 1689 | 1.91k | bool sub_constant = true; | 1690 | 2.86k | for (const auto& sub : to_sub) { | 1691 | 2.86k | sub_native += (uint512_t(sub.get_value() % modulus_u512).lo); | 1692 | 2.86k | sub_constant = sub_constant && sub.is_constant(); | 1693 | 2.86k | } | 1694 | | | 1695 | 1.91k | native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo); | 1696 | | | 1697 | | // Compute the result | 1698 | 1.91k | const native result_native = (product_native - sub_native) / divisor_native; | 1699 | | | 1700 | 1.91k | const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native))); | 1701 | | | 1702 | | // If everything is constant, then we just return the constant | 1703 | 1.91k | if (sub_constant && products_constant && divisor.is_constant()) { | 1704 | 0 | auto result = bigfield(ctx, uint256_t(result_value.lo.lo)); | 1705 | 0 | result.set_origin_tag(new_tag); | 1706 | 0 | return result; | 1707 | 0 | } | 1708 | | | 1709 | 1.91k | ASSERT(ctx != NULL); | 1710 | | // Create the result witness | 1711 | 1.91k | bigfield result = create_from_u512_as_witness(ctx, result_value.lo); | 1712 | | | 1713 | 1.91k | std::vector<bigfield> eval_left{ result }; | 1714 | 1.91k | std::vector<bigfield> eval_right{ divisor }; | 1715 | 3.81k | for (const auto& in : mul_left) { | 1716 | 3.81k | eval_left.emplace_back(in); | 1717 | 3.81k | } | 1718 | 3.81k | for (const auto& in : mul_right) { | 1719 | 3.81k | eval_right.emplace_back(in); | 1720 | 3.81k | } | 1721 | | | 1722 | 1.91k | mult_madd(eval_left, eval_right, to_sub, true); | 1723 | | | 1724 | 1.91k | result.set_origin_tag(new_tag); | 1725 | 1.91k | return result; | 1726 | 1.91k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b |
1727 | | |
1728 | | template <typename Builder, typename T> |
1729 | | bigfield<Builder, T> bigfield<Builder, T>::conditional_negate(const bool_t<Builder>& predicate) const |
1730 | 33.7k | { |
1731 | 33.7k | Builder* ctx = context ? context : predicate.context; |
1732 | | |
1733 | 33.7k | if (is_constant() && predicate.is_constant()) { |
1734 | 0 | auto result = *this; |
1735 | 0 | if (predicate.get_value()) { |
1736 | 0 | ASSERT(get_value() < modulus_u512); |
1737 | 0 | uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512; |
1738 | 0 | result = bigfield(ctx, out_val.lo); |
1739 | 0 | } |
1740 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag())); |
1741 | 0 | return result; |
1742 | 0 | } |
1743 | 33.7k | reduction_check(); |
1744 | | |
1745 | 33.7k | uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value; |
1746 | 33.7k | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
1747 | 33.7k | uint256_t limb_1_maximum_value = |
1748 | 33.7k | binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); |
1749 | 33.7k | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
1750 | 33.7k | uint256_t limb_2_maximum_value = |
1751 | 33.7k | binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); |
1752 | 33.7k | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); |
1753 | | |
1754 | 33.7k | uint256_t limb_3_maximum_value = |
1755 | 33.7k | binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); |
1756 | | |
1757 | | // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); |
1758 | | // uint256_t additive_term = comparison_maximum; |
1759 | | // TODO: This is terribly inefficient. We should change it. |
1760 | 33.7k | uint512_t constant_to_add = modulus_u512; |
1761 | 87.9k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { |
1762 | 54.2k | constant_to_add += modulus_u512; |
1763 | 54.2k | } |
1764 | | |
1765 | 33.7k | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); |
1766 | 33.7k | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); |
1767 | 33.7k | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); |
1768 | 33.7k | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); |
1769 | | |
1770 | 33.7k | uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)); |
1771 | 33.7k | uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)); |
1772 | 33.7k | uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)); |
1773 | 33.7k | uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); |
1774 | | |
1775 | 33.7k | bb::fr to_add_0(t0 + to_add_0_u256); |
1776 | 33.7k | bb::fr to_add_1(t1 + to_add_1_u256); |
1777 | 33.7k | bb::fr to_add_2(t2 + to_add_2_u256); |
1778 | 33.7k | bb::fr to_add_3(to_add_3_u256 - t3); |
1779 | | |
1780 | | // we either return current value if predicate is false, or (limb_i - value) if predicate is true |
1781 | | // (1 - predicate) * value + predicate * (limb_i - value) |
1782 | | // = predicate * (limb_i - 2 * value) + value |
1783 | 33.7k | bb::fr two(2); |
1784 | | |
1785 | 33.7k | field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0, |
1786 | 33.7k | binary_basis_limbs[0].element); |
1787 | 33.7k | field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1, |
1788 | 33.7k | binary_basis_limbs[1].element); |
1789 | 33.7k | field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2, |
1790 | 33.7k | binary_basis_limbs[2].element); |
1791 | 33.7k | field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3, |
1792 | 33.7k | binary_basis_limbs[3].element); |
1793 | | |
1794 | 33.7k | uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0; |
1795 | 33.7k | uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1; |
1796 | 33.7k | uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2; |
1797 | 33.7k | uint256_t maximum_negated_limb_3 = to_add_3_u256; |
1798 | | |
1799 | 33.7k | uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0 |
1800 | 33.7k | ? binary_basis_limbs[0].maximum_value |
1801 | 33.7k | : maximum_negated_limb_0; |
1802 | 33.7k | uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1 |
1803 | 33.7k | ? binary_basis_limbs[1].maximum_value |
1804 | 33.7k | : maximum_negated_limb_1; |
1805 | 33.7k | uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2 |
1806 | 33.7k | ? binary_basis_limbs[2].maximum_value |
1807 | 33.7k | : maximum_negated_limb_2; |
1808 | 33.7k | uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3 |
1809 | 33.7k | ? binary_basis_limbs[3].maximum_value |
1810 | 33.7k | : maximum_negated_limb_3; |
1811 | | |
1812 | 33.7k | bigfield result(ctx); |
1813 | 33.7k | result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0); |
1814 | 33.7k | result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1); |
1815 | 33.7k | result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2); |
1816 | 33.7k | result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3); |
1817 | | |
1818 | 33.7k | uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus; |
1819 | 33.7k | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); |
1820 | 33.7k | result.prime_basis_limb = |
1821 | 33.7k | static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb); |
1822 | | |
1823 | 33.7k | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag)); |
1824 | | |
1825 | 33.7k | return result; |
1826 | 33.7k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Line | Count | Source | 1730 | 33.1k | { | 1731 | 33.1k | Builder* ctx = context ? context : predicate.context; | 1732 | | | 1733 | 33.1k | if (is_constant() && predicate.is_constant()) { | 1734 | 0 | auto result = *this; | 1735 | 0 | if (predicate.get_value()) { | 1736 | 0 | ASSERT(get_value() < modulus_u512); | 1737 | 0 | uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512; | 1738 | 0 | result = bigfield(ctx, out_val.lo); | 1739 | 0 | } | 1740 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag())); | 1741 | 0 | return result; | 1742 | 0 | } | 1743 | 33.1k | reduction_check(); | 1744 | | | 1745 | 33.1k | uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value; | 1746 | 33.1k | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1747 | 33.1k | uint256_t limb_1_maximum_value = | 1748 | 33.1k | binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 1749 | 33.1k | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1750 | 33.1k | uint256_t limb_2_maximum_value = | 1751 | 33.1k | binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 1752 | 33.1k | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1753 | | | 1754 | 33.1k | uint256_t limb_3_maximum_value = | 1755 | 33.1k | binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1756 | | | 1757 | | // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1758 | | // uint256_t additive_term = comparison_maximum; | 1759 | | // TODO: This is terribly inefficient. We should change it. | 1760 | 33.1k | uint512_t constant_to_add = modulus_u512; | 1761 | 86.9k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 1762 | 53.7k | constant_to_add += modulus_u512; | 1763 | 53.7k | } | 1764 | | | 1765 | 33.1k | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 1766 | 33.1k | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 1767 | 33.1k | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 1768 | 33.1k | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1769 | | | 1770 | 33.1k | uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)); | 1771 | 33.1k | uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)); | 1772 | 33.1k | uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)); | 1773 | 33.1k | uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1774 | | | 1775 | 33.1k | bb::fr to_add_0(t0 + to_add_0_u256); | 1776 | 33.1k | bb::fr to_add_1(t1 + to_add_1_u256); | 1777 | 33.1k | bb::fr to_add_2(t2 + to_add_2_u256); | 1778 | 33.1k | bb::fr to_add_3(to_add_3_u256 - t3); | 1779 | | | 1780 | | // we either return current value if predicate is false, or (limb_i - value) if predicate is true | 1781 | | // (1 - predicate) * value + predicate * (limb_i - value) | 1782 | | // = predicate * (limb_i - 2 * value) + value | 1783 | 33.1k | bb::fr two(2); | 1784 | | | 1785 | 33.1k | field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0, | 1786 | 33.1k | binary_basis_limbs[0].element); | 1787 | 33.1k | field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1, | 1788 | 33.1k | binary_basis_limbs[1].element); | 1789 | 33.1k | field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2, | 1790 | 33.1k | binary_basis_limbs[2].element); | 1791 | 33.1k | field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3, | 1792 | 33.1k | binary_basis_limbs[3].element); | 1793 | | | 1794 | 33.1k | uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0; | 1795 | 33.1k | uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1; | 1796 | 33.1k | uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2; | 1797 | 33.1k | uint256_t maximum_negated_limb_3 = to_add_3_u256; | 1798 | | | 1799 | 33.1k | uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0 | 1800 | 33.1k | ? binary_basis_limbs[0].maximum_value | 1801 | 33.1k | : maximum_negated_limb_0; | 1802 | 33.1k | uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1 | 1803 | 33.1k | ? binary_basis_limbs[1].maximum_value | 1804 | 33.1k | : maximum_negated_limb_1; | 1805 | 33.1k | uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2 | 1806 | 33.1k | ? binary_basis_limbs[2].maximum_value | 1807 | 33.1k | : maximum_negated_limb_2; | 1808 | 33.1k | uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3 | 1809 | 33.1k | ? binary_basis_limbs[3].maximum_value | 1810 | 33.1k | : maximum_negated_limb_3; | 1811 | | | 1812 | 33.1k | bigfield result(ctx); | 1813 | 33.1k | result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0); | 1814 | 33.1k | result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1); | 1815 | 33.1k | result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2); | 1816 | 33.1k | result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3); | 1817 | | | 1818 | 33.1k | uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus; | 1819 | 33.1k | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 1820 | 33.1k | result.prime_basis_limb = | 1821 | 33.1k | static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb); | 1822 | | | 1823 | 33.1k | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag)); | 1824 | | | 1825 | 33.1k | return result; | 1826 | 33.1k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Line | Count | Source | 1730 | 24 | { | 1731 | 24 | Builder* ctx = context ? context : predicate.context; | 1732 | | | 1733 | 24 | if (is_constant() && predicate.is_constant()) { | 1734 | 0 | auto result = *this; | 1735 | 0 | if (predicate.get_value()) { | 1736 | 0 | ASSERT(get_value() < modulus_u512); | 1737 | 0 | uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512; | 1738 | 0 | result = bigfield(ctx, out_val.lo); | 1739 | 0 | } | 1740 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag())); | 1741 | 0 | return result; | 1742 | 0 | } | 1743 | 24 | reduction_check(); | 1744 | | | 1745 | 24 | uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value; | 1746 | 24 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1747 | 24 | uint256_t limb_1_maximum_value = | 1748 | 24 | binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 1749 | 24 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1750 | 24 | uint256_t limb_2_maximum_value = | 1751 | 24 | binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 1752 | 24 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1753 | | | 1754 | 24 | uint256_t limb_3_maximum_value = | 1755 | 24 | binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1756 | | | 1757 | | // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1758 | | // uint256_t additive_term = comparison_maximum; | 1759 | | // TODO: This is terribly inefficient. We should change it. | 1760 | 24 | uint512_t constant_to_add = modulus_u512; | 1761 | 42 | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 1762 | 18 | constant_to_add += modulus_u512; | 1763 | 18 | } | 1764 | | | 1765 | 24 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 1766 | 24 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 1767 | 24 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 1768 | 24 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1769 | | | 1770 | 24 | uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)); | 1771 | 24 | uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)); | 1772 | 24 | uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)); | 1773 | 24 | uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1774 | | | 1775 | 24 | bb::fr to_add_0(t0 + to_add_0_u256); | 1776 | 24 | bb::fr to_add_1(t1 + to_add_1_u256); | 1777 | 24 | bb::fr to_add_2(t2 + to_add_2_u256); | 1778 | 24 | bb::fr to_add_3(to_add_3_u256 - t3); | 1779 | | | 1780 | | // we either return current value if predicate is false, or (limb_i - value) if predicate is true | 1781 | | // (1 - predicate) * value + predicate * (limb_i - value) | 1782 | | // = predicate * (limb_i - 2 * value) + value | 1783 | 24 | bb::fr two(2); | 1784 | | | 1785 | 24 | field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0, | 1786 | 24 | binary_basis_limbs[0].element); | 1787 | 24 | field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1, | 1788 | 24 | binary_basis_limbs[1].element); | 1789 | 24 | field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2, | 1790 | 24 | binary_basis_limbs[2].element); | 1791 | 24 | field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3, | 1792 | 24 | binary_basis_limbs[3].element); | 1793 | | | 1794 | 24 | uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0; | 1795 | 24 | uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1; | 1796 | 24 | uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2; | 1797 | 24 | uint256_t maximum_negated_limb_3 = to_add_3_u256; | 1798 | | | 1799 | 24 | uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0 | 1800 | 24 | ? binary_basis_limbs[0].maximum_value | 1801 | 24 | : maximum_negated_limb_0; | 1802 | 24 | uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1 | 1803 | 24 | ? binary_basis_limbs[1].maximum_value | 1804 | 24 | : maximum_negated_limb_1; | 1805 | 24 | uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2 | 1806 | 24 | ? binary_basis_limbs[2].maximum_value | 1807 | 24 | : maximum_negated_limb_2; | 1808 | 24 | uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3 | 1809 | 24 | ? binary_basis_limbs[3].maximum_value | 1810 | 24 | : maximum_negated_limb_3; | 1811 | | | 1812 | 24 | bigfield result(ctx); | 1813 | 24 | result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0); | 1814 | 24 | result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1); | 1815 | 24 | result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2); | 1816 | 24 | result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3); | 1817 | | | 1818 | 24 | uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus; | 1819 | 24 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 1820 | 24 | result.prime_basis_limb = | 1821 | 24 | static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb); | 1822 | | | 1823 | 24 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag)); | 1824 | | | 1825 | 24 | return result; | 1826 | 24 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Line | Count | Source | 1730 | 576 | { | 1731 | 576 | Builder* ctx = context ? context : predicate.context; | 1732 | | | 1733 | 576 | if (is_constant() && predicate.is_constant()) { | 1734 | 0 | auto result = *this; | 1735 | 0 | if (predicate.get_value()) { | 1736 | 0 | ASSERT(get_value() < modulus_u512); | 1737 | 0 | uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512; | 1738 | 0 | result = bigfield(ctx, out_val.lo); | 1739 | 0 | } | 1740 | 0 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag())); | 1741 | 0 | return result; | 1742 | 0 | } | 1743 | 576 | reduction_check(); | 1744 | | | 1745 | 576 | uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value; | 1746 | 576 | uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1747 | 576 | uint256_t limb_1_maximum_value = | 1748 | 576 | binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)); | 1749 | 576 | uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1750 | 576 | uint256_t limb_2_maximum_value = | 1751 | 576 | binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)); | 1752 | 576 | uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS); | 1753 | | | 1754 | 576 | uint256_t limb_3_maximum_value = | 1755 | 576 | binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1756 | | | 1757 | | // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1758 | | // uint256_t additive_term = comparison_maximum; | 1759 | | // TODO: This is terribly inefficient. We should change it. | 1760 | 576 | uint512_t constant_to_add = modulus_u512; | 1761 | 1.00k | while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) { | 1762 | 432 | constant_to_add += modulus_u512; | 1763 | 432 | } | 1764 | | | 1765 | 576 | uint256_t t0(uint256_t(1) << limb_0_borrow_shift); | 1766 | 576 | uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS))); | 1767 | 576 | uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS))); | 1768 | 576 | uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS)); | 1769 | | | 1770 | 576 | uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)); | 1771 | 576 | uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)); | 1772 | 576 | uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)); | 1773 | 576 | uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); | 1774 | | | 1775 | 576 | bb::fr to_add_0(t0 + to_add_0_u256); | 1776 | 576 | bb::fr to_add_1(t1 + to_add_1_u256); | 1777 | 576 | bb::fr to_add_2(t2 + to_add_2_u256); | 1778 | 576 | bb::fr to_add_3(to_add_3_u256 - t3); | 1779 | | | 1780 | | // we either return current value if predicate is false, or (limb_i - value) if predicate is true | 1781 | | // (1 - predicate) * value + predicate * (limb_i - value) | 1782 | | // = predicate * (limb_i - 2 * value) + value | 1783 | 576 | bb::fr two(2); | 1784 | | | 1785 | 576 | field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0, | 1786 | 576 | binary_basis_limbs[0].element); | 1787 | 576 | field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1, | 1788 | 576 | binary_basis_limbs[1].element); | 1789 | 576 | field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2, | 1790 | 576 | binary_basis_limbs[2].element); | 1791 | 576 | field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3, | 1792 | 576 | binary_basis_limbs[3].element); | 1793 | | | 1794 | 576 | uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0; | 1795 | 576 | uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1; | 1796 | 576 | uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2; | 1797 | 576 | uint256_t maximum_negated_limb_3 = to_add_3_u256; | 1798 | | | 1799 | 576 | uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0 | 1800 | 576 | ? binary_basis_limbs[0].maximum_value | 1801 | 576 | : maximum_negated_limb_0; | 1802 | 576 | uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1 | 1803 | 576 | ? binary_basis_limbs[1].maximum_value | 1804 | 576 | : maximum_negated_limb_1; | 1805 | 576 | uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2 | 1806 | 576 | ? binary_basis_limbs[2].maximum_value | 1807 | 576 | : maximum_negated_limb_2; | 1808 | 576 | uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3 | 1809 | 576 | ? binary_basis_limbs[3].maximum_value | 1810 | 576 | : maximum_negated_limb_3; | 1811 | | | 1812 | 576 | bigfield result(ctx); | 1813 | 576 | result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0); | 1814 | 576 | result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1); | 1815 | 576 | result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2); | 1816 | 576 | result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3); | 1817 | | | 1818 | 576 | uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus; | 1819 | 576 | field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo)); | 1820 | 576 | result.prime_basis_limb = | 1821 | 576 | static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb); | 1822 | | | 1823 | 576 | result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag)); | 1824 | | | 1825 | 576 | return result; | 1826 | 576 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE |
1827 | | |
1828 | | /** |
1829 | | * @brief Create an element which is equal to either this or other based on the predicate |
1830 | | * |
1831 | | * @tparam Builder |
1832 | | * @tparam T |
1833 | | * @param other The other bigfield element |
1834 | | * @param predicate Predicate controlling the result (0 for this, 1 for the other) |
1835 | | * @return Resulting element |
1836 | | */ |
1837 | | template <typename Builder, typename T> |
1838 | | bigfield<Builder, T> bigfield<Builder, T>::conditional_select(const bigfield& other, |
1839 | | const bool_t<Builder>& predicate) const |
1840 | 154k | { |
1841 | 154k | if (is_constant() && other.is_constant() && predicate.is_constant()) { |
1842 | 186 | if (predicate.get_value()) { |
1843 | 11 | return other; |
1844 | 11 | } |
1845 | 175 | return *this; |
1846 | 186 | } |
1847 | 154k | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); |
1848 | | |
1849 | | // TODO: use field_t::conditional_assign method |
1850 | 154k | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( |
1851 | 154k | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); |
1852 | 154k | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( |
1853 | 154k | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); |
1854 | 154k | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( |
1855 | 154k | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); |
1856 | 154k | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( |
1857 | 154k | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); |
1858 | 154k | field_t prime_limb = |
1859 | 154k | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); |
1860 | | |
1861 | 154k | bigfield result(ctx); |
1862 | | // the maximum of the maximal values of elements is large enough |
1863 | 154k | result.binary_basis_limbs[0] = |
1864 | 154k | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); |
1865 | 154k | result.binary_basis_limbs[1] = |
1866 | 154k | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); |
1867 | 154k | result.binary_basis_limbs[2] = |
1868 | 154k | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); |
1869 | 154k | result.binary_basis_limbs[3] = |
1870 | 154k | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); |
1871 | 154k | result.prime_basis_limb = prime_limb; |
1872 | 154k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); |
1873 | 154k | return result; |
1874 | 154k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE Line | Count | Source | 1840 | 137k | { | 1841 | 137k | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 165 | if (predicate.get_value()) { | 1843 | 11 | return other; | 1844 | 11 | } | 1845 | 154 | return *this; | 1846 | 165 | } | 1847 | 137k | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 137k | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 137k | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 137k | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 137k | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 137k | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 137k | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 137k | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 137k | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 137k | field_t prime_limb = | 1859 | 137k | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 137k | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 137k | result.binary_basis_limbs[0] = | 1864 | 137k | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 137k | result.binary_basis_limbs[1] = | 1866 | 137k | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 137k | result.binary_basis_limbs[2] = | 1868 | 137k | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 137k | result.binary_basis_limbs[3] = | 1870 | 137k | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 137k | result.prime_basis_limb = prime_limb; | 1872 | 137k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 137k | return result; | 1874 | 137k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE Line | Count | Source | 1840 | 50 | { | 1841 | 50 | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 0 | if (predicate.get_value()) { | 1843 | 0 | return other; | 1844 | 0 | } | 1845 | 0 | return *this; | 1846 | 0 | } | 1847 | 50 | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 50 | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 50 | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 50 | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 50 | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 50 | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 50 | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 50 | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 50 | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 50 | field_t prime_limb = | 1859 | 50 | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 50 | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 50 | result.binary_basis_limbs[0] = | 1864 | 50 | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 50 | result.binary_basis_limbs[1] = | 1866 | 50 | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 50 | result.binary_basis_limbs[2] = | 1868 | 50 | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 50 | result.binary_basis_limbs[3] = | 1870 | 50 | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 50 | result.prime_basis_limb = prime_limb; | 1872 | 50 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 50 | return result; | 1874 | 50 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_selectERKS8_RKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_selectERKS7_RKNS0_6bool_tIS6_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE Line | Count | Source | 1840 | 669 | { | 1841 | 669 | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 3 | if (predicate.get_value()) { | 1843 | 0 | return other; | 1844 | 0 | } | 1845 | 3 | return *this; | 1846 | 3 | } | 1847 | 666 | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 666 | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 666 | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 666 | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 666 | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 666 | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 666 | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 666 | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 666 | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 666 | field_t prime_limb = | 1859 | 666 | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 666 | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 666 | result.binary_basis_limbs[0] = | 1864 | 666 | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 666 | result.binary_basis_limbs[1] = | 1866 | 666 | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 666 | result.binary_basis_limbs[2] = | 1868 | 666 | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 666 | result.binary_basis_limbs[3] = | 1870 | 666 | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 666 | result.prime_basis_limb = prime_limb; | 1872 | 666 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 666 | return result; | 1874 | 669 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE Line | Count | Source | 1840 | 16.2k | { | 1841 | 16.2k | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 0 | if (predicate.get_value()) { | 1843 | 0 | return other; | 1844 | 0 | } | 1845 | 0 | return *this; | 1846 | 0 | } | 1847 | 16.2k | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 16.2k | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 16.2k | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 16.2k | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 16.2k | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 16.2k | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 16.2k | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 16.2k | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 16.2k | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 16.2k | field_t prime_limb = | 1859 | 16.2k | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 16.2k | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 16.2k | result.binary_basis_limbs[0] = | 1864 | 16.2k | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 16.2k | result.binary_basis_limbs[1] = | 1866 | 16.2k | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 16.2k | result.binary_basis_limbs[2] = | 1868 | 16.2k | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 16.2k | result.binary_basis_limbs[3] = | 1870 | 16.2k | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 16.2k | result.prime_basis_limb = prime_limb; | 1872 | 16.2k | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 16.2k | return result; | 1874 | 16.2k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE Line | Count | Source | 1840 | 199 | { | 1841 | 199 | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 18 | if (predicate.get_value()) { | 1843 | 0 | return other; | 1844 | 0 | } | 1845 | 18 | return *this; | 1846 | 18 | } | 1847 | 181 | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 181 | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 181 | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 181 | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 181 | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 181 | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 181 | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 181 | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 181 | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 181 | field_t prime_limb = | 1859 | 181 | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 181 | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 181 | result.binary_basis_limbs[0] = | 1864 | 181 | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 181 | result.binary_basis_limbs[1] = | 1866 | 181 | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 181 | result.binary_basis_limbs[2] = | 1868 | 181 | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 181 | result.binary_basis_limbs[3] = | 1870 | 181 | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 181 | result.prime_basis_limb = prime_limb; | 1872 | 181 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 181 | return result; | 1874 | 199 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE Line | Count | Source | 1840 | 10 | { | 1841 | 10 | if (is_constant() && other.is_constant() && predicate.is_constant()) { | 1842 | 0 | if (predicate.get_value()) { | 1843 | 0 | return other; | 1844 | 0 | } | 1845 | 0 | return *this; | 1846 | 0 | } | 1847 | 10 | Builder* ctx = context ? context : (other.context ? other.context : predicate.context); | 1848 | | | 1849 | | // TODO: use field_t::conditional_assign method | 1850 | 10 | field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd( | 1851 | 10 | other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element); | 1852 | 10 | field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd( | 1853 | 10 | other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element); | 1854 | 10 | field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd( | 1855 | 10 | other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element); | 1856 | 10 | field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd( | 1857 | 10 | other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element); | 1858 | 10 | field_t prime_limb = | 1859 | 10 | static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb); | 1860 | | | 1861 | 10 | bigfield result(ctx); | 1862 | | // the maximum of the maximal values of elements is large enough | 1863 | 10 | result.binary_basis_limbs[0] = | 1864 | 10 | Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value)); | 1865 | 10 | result.binary_basis_limbs[1] = | 1866 | 10 | Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value)); | 1867 | 10 | result.binary_basis_limbs[2] = | 1868 | 10 | Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value)); | 1869 | 10 | result.binary_basis_limbs[3] = | 1870 | 10 | Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value)); | 1871 | 10 | result.prime_basis_limb = prime_limb; | 1872 | 10 | result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag)); | 1873 | 10 | return result; | 1874 | 10 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE |
1875 | | |
1876 | | /** |
1877 | | * @brief Validate whether two bigfield elements are equal to each other |
1878 | | * @details To evaluate whether `(a == b)`, we use result boolean `r` to evaluate the following logic: |
1879 | | * (n.b all algebra involving bigfield elements is done in the bigfield) |
1880 | | * 1. If `r == 1` , `a - b == 0` |
1881 | | * 2. If `r == 0`, `a - b` posesses an inverse `I` i.e. `(a - b) * I - 1 == 0` |
1882 | | * We efficiently evaluate this logic by evaluating a single expression `(a - b)*X = Y` |
1883 | | * We use conditional assignment logic to define `X, Y` to be the following: |
1884 | | * If `r == 1` then `X = 1, Y = 0` |
1885 | | * If `r == 0` then `X = I, Y = 1` |
1886 | | * This allows us to evaluate `operator==` using only 1 bigfield multiplication operation. |
1887 | | * We can check the product equals 0 or 1 by directly evaluating the binary basis/prime basis limbs of Y. |
1888 | | * i.e. if `r == 1` then `(a - b)*X` should have 0 for all limb values |
1889 | | * if `r == 0` then `(a - b)*X` should have 1 in the least significant binary basis limb and 0 |
1890 | | * elsewhere |
1891 | | * @tparam Builder |
1892 | | * @tparam T |
1893 | | * @param other |
1894 | | * @return bool_t<Builder> |
1895 | | */ |
1896 | | template <typename Builder, typename T> bool_t<Builder> bigfield<Builder, T>::operator==(const bigfield& other) const |
1897 | 27.3k | { |
1898 | 27.3k | Builder* ctx = context ? context : other.get_context(); |
1899 | 27.3k | auto lhs = get_value() % modulus_u512; |
1900 | 27.3k | auto rhs = other.get_value() % modulus_u512; |
1901 | 27.3k | bool is_equal_raw = (lhs == rhs); |
1902 | 27.3k | if (!ctx) { |
1903 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are |
1904 | | // constant, but we check with an assertion to be sure. |
1905 | 0 | ASSERT(is_constant() && other.is_constant()); |
1906 | 0 | return is_equal_raw; |
1907 | 0 | } |
1908 | 27.3k | bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw); |
1909 | | |
1910 | 27.3k | bigfield diff = (*this) - other; |
1911 | | |
1912 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512 |
1913 | | // value fits in a u256, subtract off modulus until u256 fits into finite field) |
1914 | 27.3k | native diff_native = native((diff.get_value() % modulus_u512).lo); |
1915 | 27.3k | native inverse_native = is_equal_raw ? 0 : diff_native.invert(); |
1916 | | |
1917 | 27.3k | bigfield inverse = bigfield::from_witness(ctx, inverse_native); |
1918 | | |
1919 | 27.3k | bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse); |
1920 | | |
1921 | 27.3k | bigfield product = diff * multiplicand; |
1922 | | |
1923 | 27.3k | field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1); |
1924 | | |
1925 | 27.3k | product.prime_basis_limb.assert_equal(result); |
1926 | 27.3k | product.binary_basis_limbs[0].element.assert_equal(result); |
1927 | 27.3k | product.binary_basis_limbs[1].element.assert_equal(0); |
1928 | 27.3k | product.binary_basis_limbs[2].element.assert_equal(0); |
1929 | 27.3k | product.binary_basis_limbs[3].element.assert_equal(0); |
1930 | 27.3k | is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); |
1931 | 27.3k | return is_equal; |
1932 | 27.3k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_ Line | Count | Source | 1897 | 23.9k | { | 1898 | 23.9k | Builder* ctx = context ? context : other.get_context(); | 1899 | 23.9k | auto lhs = get_value() % modulus_u512; | 1900 | 23.9k | auto rhs = other.get_value() % modulus_u512; | 1901 | 23.9k | bool is_equal_raw = (lhs == rhs); | 1902 | 23.9k | if (!ctx) { | 1903 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are | 1904 | | // constant, but we check with an assertion to be sure. | 1905 | 0 | ASSERT(is_constant() && other.is_constant()); | 1906 | 0 | return is_equal_raw; | 1907 | 0 | } | 1908 | 23.9k | bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw); | 1909 | | | 1910 | 23.9k | bigfield diff = (*this) - other; | 1911 | | | 1912 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512 | 1913 | | // value fits in a u256, subtract off modulus until u256 fits into finite field) | 1914 | 23.9k | native diff_native = native((diff.get_value() % modulus_u512).lo); | 1915 | 23.9k | native inverse_native = is_equal_raw ? 0 : diff_native.invert(); | 1916 | | | 1917 | 23.9k | bigfield inverse = bigfield::from_witness(ctx, inverse_native); | 1918 | | | 1919 | 23.9k | bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse); | 1920 | | | 1921 | 23.9k | bigfield product = diff * multiplicand; | 1922 | | | 1923 | 23.9k | field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1); | 1924 | | | 1925 | 23.9k | product.prime_basis_limb.assert_equal(result); | 1926 | 23.9k | product.binary_basis_limbs[0].element.assert_equal(result); | 1927 | 23.9k | product.binary_basis_limbs[1].element.assert_equal(0); | 1928 | 23.9k | product.binary_basis_limbs[2].element.assert_equal(0); | 1929 | 23.9k | product.binary_basis_limbs[3].element.assert_equal(0); | 1930 | 23.9k | is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 1931 | 23.9k | return is_equal; | 1932 | 23.9k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEeqERKS7_ Line | Count | Source | 1897 | 132 | { | 1898 | 132 | Builder* ctx = context ? context : other.get_context(); | 1899 | 132 | auto lhs = get_value() % modulus_u512; | 1900 | 132 | auto rhs = other.get_value() % modulus_u512; | 1901 | 132 | bool is_equal_raw = (lhs == rhs); | 1902 | 132 | if (!ctx) { | 1903 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are | 1904 | | // constant, but we check with an assertion to be sure. | 1905 | 0 | ASSERT(is_constant() && other.is_constant()); | 1906 | 0 | return is_equal_raw; | 1907 | 0 | } | 1908 | 132 | bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw); | 1909 | | | 1910 | 132 | bigfield diff = (*this) - other; | 1911 | | | 1912 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512 | 1913 | | // value fits in a u256, subtract off modulus until u256 fits into finite field) | 1914 | 132 | native diff_native = native((diff.get_value() % modulus_u512).lo); | 1915 | 132 | native inverse_native = is_equal_raw ? 0 : diff_native.invert(); | 1916 | | | 1917 | 132 | bigfield inverse = bigfield::from_witness(ctx, inverse_native); | 1918 | | | 1919 | 132 | bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse); | 1920 | | | 1921 | 132 | bigfield product = diff * multiplicand; | 1922 | | | 1923 | 132 | field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1); | 1924 | | | 1925 | 132 | product.prime_basis_limb.assert_equal(result); | 1926 | 132 | product.binary_basis_limbs[0].element.assert_equal(result); | 1927 | 132 | product.binary_basis_limbs[1].element.assert_equal(0); | 1928 | 132 | product.binary_basis_limbs[2].element.assert_equal(0); | 1929 | 132 | product.binary_basis_limbs[3].element.assert_equal(0); | 1930 | 132 | is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 1931 | 132 | return is_equal; | 1932 | 132 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEeqERKS7_ _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEeqERKS9_ Line | Count | Source | 1897 | 3.16k | { | 1898 | 3.16k | Builder* ctx = context ? context : other.get_context(); | 1899 | 3.16k | auto lhs = get_value() % modulus_u512; | 1900 | 3.16k | auto rhs = other.get_value() % modulus_u512; | 1901 | 3.16k | bool is_equal_raw = (lhs == rhs); | 1902 | 3.16k | if (!ctx) { | 1903 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are | 1904 | | // constant, but we check with an assertion to be sure. | 1905 | 0 | ASSERT(is_constant() && other.is_constant()); | 1906 | 0 | return is_equal_raw; | 1907 | 0 | } | 1908 | 3.16k | bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw); | 1909 | | | 1910 | 3.16k | bigfield diff = (*this) - other; | 1911 | | | 1912 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512 | 1913 | | // value fits in a u256, subtract off modulus until u256 fits into finite field) | 1914 | 3.16k | native diff_native = native((diff.get_value() % modulus_u512).lo); | 1915 | 3.16k | native inverse_native = is_equal_raw ? 0 : diff_native.invert(); | 1916 | | | 1917 | 3.16k | bigfield inverse = bigfield::from_witness(ctx, inverse_native); | 1918 | | | 1919 | 3.16k | bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse); | 1920 | | | 1921 | 3.16k | bigfield product = diff * multiplicand; | 1922 | | | 1923 | 3.16k | field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1); | 1924 | | | 1925 | 3.16k | product.prime_basis_limb.assert_equal(result); | 1926 | 3.16k | product.binary_basis_limbs[0].element.assert_equal(result); | 1927 | 3.16k | product.binary_basis_limbs[1].element.assert_equal(0); | 1928 | 3.16k | product.binary_basis_limbs[2].element.assert_equal(0); | 1929 | 3.16k | product.binary_basis_limbs[3].element.assert_equal(0); | 1930 | 3.16k | is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 1931 | 3.16k | return is_equal; | 1932 | 3.16k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEeqERKS9_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEeqERKS7_ Line | Count | Source | 1897 | 30 | { | 1898 | 30 | Builder* ctx = context ? context : other.get_context(); | 1899 | 30 | auto lhs = get_value() % modulus_u512; | 1900 | 30 | auto rhs = other.get_value() % modulus_u512; | 1901 | 30 | bool is_equal_raw = (lhs == rhs); | 1902 | 30 | if (!ctx) { | 1903 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are | 1904 | | // constant, but we check with an assertion to be sure. | 1905 | 0 | ASSERT(is_constant() && other.is_constant()); | 1906 | 0 | return is_equal_raw; | 1907 | 0 | } | 1908 | 30 | bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw); | 1909 | | | 1910 | 30 | bigfield diff = (*this) - other; | 1911 | | | 1912 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512 | 1913 | | // value fits in a u256, subtract off modulus until u256 fits into finite field) | 1914 | 30 | native diff_native = native((diff.get_value() % modulus_u512).lo); | 1915 | 30 | native inverse_native = is_equal_raw ? 0 : diff_native.invert(); | 1916 | | | 1917 | 30 | bigfield inverse = bigfield::from_witness(ctx, inverse_native); | 1918 | | | 1919 | 30 | bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse); | 1920 | | | 1921 | 30 | bigfield product = diff * multiplicand; | 1922 | | | 1923 | 30 | field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1); | 1924 | | | 1925 | 30 | product.prime_basis_limb.assert_equal(result); | 1926 | 30 | product.binary_basis_limbs[0].element.assert_equal(result); | 1927 | 30 | product.binary_basis_limbs[1].element.assert_equal(0); | 1928 | 30 | product.binary_basis_limbs[2].element.assert_equal(0); | 1929 | 30 | product.binary_basis_limbs[3].element.assert_equal(0); | 1930 | 30 | is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag())); | 1931 | 30 | return is_equal; | 1932 | 30 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEeqERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEeqERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEeqERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_ |
1933 | | |
1934 | | /** |
1935 | | * REDUCTION CHECK |
1936 | | * |
1937 | | * When performing bigfield operations, we need to ensure the maximum value is less than: |
1938 | | * sqrt(2^{272} * native_modulus) |
1939 | | * |
1940 | | * We also need to ensure each binary basis limb is less than the maximum limb value |
1941 | | * |
1942 | | * This prevents our field arithmetic from overflowing the native modulus boundary, whilst ensuring we can |
1943 | | * still use the chinese remainder theorem to validate field multiplications with a reduced number of range checks |
1944 | | * |
1945 | | **/ |
1946 | | template <typename Builder, typename T> void bigfield<Builder, T>::reduction_check() const |
1947 | 9.68M | { |
1948 | | |
1949 | 9.68M | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction |
1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? |
1951 | 1.15M | uint256_t reduced_value = (get_value() % modulus_u512).lo; |
1952 | 1.15M | bigfield reduced(context, uint256_t(reduced_value)); |
1953 | | // Save tags |
1954 | 1.15M | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), |
1955 | 1.15M | binary_basis_limbs[1].element.get_origin_tag(), |
1956 | 1.15M | binary_basis_limbs[2].element.get_origin_tag(), |
1957 | 1.15M | binary_basis_limbs[3].element.get_origin_tag(), |
1958 | 1.15M | prime_basis_limb.get_origin_tag() }); |
1959 | 1.15M | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; |
1960 | 1.15M | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; |
1961 | 1.15M | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; |
1962 | 1.15M | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; |
1963 | 1.15M | prime_basis_limb = reduced.prime_basis_limb; |
1964 | | // Preserve origin tags (useful in simulator) |
1965 | 1.15M | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); |
1966 | 1.15M | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); |
1967 | 1.15M | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); |
1968 | 1.15M | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); |
1969 | 1.15M | prime_basis_limb.set_origin_tag(origin_tags[4]); |
1970 | 1.15M | return; |
1971 | 1.15M | } |
1972 | | |
1973 | 8.52M | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); |
1974 | 8.52M | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; |
1975 | 8.52M | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; |
1976 | 8.52M | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; |
1977 | 8.52M | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; |
1978 | 8.52M | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || |
1979 | 8.52M | limb_overflow_test_2 || limb_overflow_test_3) { |
1980 | 96 | self_reduce(); |
1981 | 96 | } |
1982 | 8.52M | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE15reduction_checkEv Line | Count | Source | 1947 | 8.82M | { | 1948 | | | 1949 | 8.82M | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 1.05M | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 1.05M | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 1.05M | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 1.05M | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 1.05M | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 1.05M | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 1.05M | prime_basis_limb.get_origin_tag() }); | 1959 | 1.05M | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 1.05M | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 1.05M | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 1.05M | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 1.05M | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 1.05M | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 1.05M | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 1.05M | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 1.05M | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 1.05M | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 1.05M | return; | 1971 | 1.05M | } | 1972 | | | 1973 | 7.76M | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 7.76M | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 7.76M | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 7.76M | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 7.76M | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 7.76M | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 7.76M | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 90 | self_reduce(); | 1981 | 90 | } | 1982 | 7.76M | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE15reduction_checkEv Line | Count | Source | 1947 | 1.46k | { | 1948 | | | 1949 | 1.46k | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 56 | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 56 | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 56 | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 56 | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 56 | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 56 | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 56 | prime_basis_limb.get_origin_tag() }); | 1959 | 56 | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 56 | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 56 | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 56 | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 56 | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 56 | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 56 | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 56 | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 56 | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 56 | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 56 | return; | 1971 | 56 | } | 1972 | | | 1973 | 1.40k | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 1.40k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 1.40k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 1.40k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 1.40k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 1.40k | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 1.40k | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 6 | self_reduce(); | 1981 | 6 | } | 1982 | 1.40k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE15reduction_checkEv Line | Count | Source | 1947 | 40 | { | 1948 | | | 1949 | 40 | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 8 | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 8 | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 8 | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 8 | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 8 | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 8 | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 8 | prime_basis_limb.get_origin_tag() }); | 1959 | 8 | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 8 | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 8 | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 8 | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 8 | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 8 | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 8 | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 8 | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 8 | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 8 | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 8 | return; | 1971 | 8 | } | 1972 | | | 1973 | 32 | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 32 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 32 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 32 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 32 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 32 | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 32 | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 32 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E15reduction_checkEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE15reduction_checkEv Line | Count | Source | 1947 | 34.7k | { | 1948 | | | 1949 | 34.7k | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 4.11k | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 4.11k | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 4.11k | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 4.11k | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 4.11k | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 4.11k | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 4.11k | prime_basis_limb.get_origin_tag() }); | 1959 | 4.11k | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 4.11k | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 4.11k | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 4.11k | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 4.11k | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 4.11k | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 4.11k | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 4.11k | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 4.11k | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 4.11k | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 4.11k | return; | 1971 | 4.11k | } | 1972 | | | 1973 | 30.5k | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 30.5k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 30.5k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 30.5k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 30.5k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 30.5k | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 30.5k | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 30.5k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE15reduction_checkEv Line | Count | Source | 1947 | 216 | { | 1948 | | | 1949 | 216 | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 36 | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 36 | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 36 | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 36 | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 36 | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 36 | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 36 | prime_basis_limb.get_origin_tag() }); | 1959 | 36 | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 36 | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 36 | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 36 | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 36 | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 36 | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 36 | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 36 | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 36 | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 36 | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 36 | return; | 1971 | 36 | } | 1972 | | | 1973 | 180 | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 180 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 180 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 180 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 180 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 180 | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 180 | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 180 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE15reduction_checkEv Line | Count | Source | 1947 | 763k | { | 1948 | | | 1949 | 763k | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 91.2k | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 91.2k | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 91.2k | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 91.2k | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 91.2k | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 91.2k | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 91.2k | prime_basis_limb.get_origin_tag() }); | 1959 | 91.2k | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 91.2k | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 91.2k | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 91.2k | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 91.2k | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 91.2k | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 91.2k | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 91.2k | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 91.2k | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 91.2k | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 91.2k | return; | 1971 | 91.2k | } | 1972 | | | 1973 | 672k | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 672k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 672k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 672k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 672k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 672k | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 672k | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 672k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE15reduction_checkEv Line | Count | Source | 1947 | 4.89k | { | 1948 | | | 1949 | 4.89k | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 864 | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 864 | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 864 | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 864 | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 864 | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 864 | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 864 | prime_basis_limb.get_origin_tag() }); | 1959 | 864 | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 864 | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 864 | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 864 | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 864 | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 864 | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 864 | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 864 | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 864 | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 864 | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 864 | return; | 1971 | 864 | } | 1972 | | | 1973 | 4.03k | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 4.03k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 4.03k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 4.03k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 4.03k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 4.03k | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 4.03k | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 4.03k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE15reduction_checkEv Line | Count | Source | 1947 | 56.4k | { | 1948 | | | 1949 | 56.4k | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 6.05k | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 6.05k | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 6.05k | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 6.05k | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 6.05k | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 6.05k | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 6.05k | prime_basis_limb.get_origin_tag() }); | 1959 | 6.05k | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 6.05k | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 6.05k | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 6.05k | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 6.05k | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 6.05k | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 6.05k | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 6.05k | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 6.05k | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 6.05k | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 6.05k | return; | 1971 | 6.05k | } | 1972 | | | 1973 | 50.3k | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 50.3k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 50.3k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 50.3k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 50.3k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 50.3k | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 50.3k | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 50.3k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE15reduction_checkEv Line | Count | Source | 1947 | 60 | { | 1948 | | | 1949 | 60 | if (is_constant()) { // this seems not a reduction check, but actually computing the reduction | 1950 | | // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED? | 1951 | 0 | uint256_t reduced_value = (get_value() % modulus_u512).lo; | 1952 | 0 | bigfield reduced(context, uint256_t(reduced_value)); | 1953 | | // Save tags | 1954 | 0 | const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(), | 1955 | 0 | binary_basis_limbs[1].element.get_origin_tag(), | 1956 | 0 | binary_basis_limbs[2].element.get_origin_tag(), | 1957 | 0 | binary_basis_limbs[3].element.get_origin_tag(), | 1958 | 0 | prime_basis_limb.get_origin_tag() }); | 1959 | 0 | binary_basis_limbs[0] = reduced.binary_basis_limbs[0]; | 1960 | 0 | binary_basis_limbs[1] = reduced.binary_basis_limbs[1]; | 1961 | 0 | binary_basis_limbs[2] = reduced.binary_basis_limbs[2]; | 1962 | 0 | binary_basis_limbs[3] = reduced.binary_basis_limbs[3]; | 1963 | 0 | prime_basis_limb = reduced.prime_basis_limb; | 1964 | | // Preserve origin tags (useful in simulator) | 1965 | 0 | binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]); | 1966 | 0 | binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]); | 1967 | 0 | binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]); | 1968 | 0 | binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]); | 1969 | 0 | prime_basis_limb.set_origin_tag(origin_tags[4]); | 1970 | 0 | return; | 1971 | 0 | } | 1972 | | | 1973 | 60 | uint256_t maximum_limb_value = get_maximum_unreduced_limb_value(); | 1974 | 60 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1975 | 60 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1976 | 60 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1977 | 60 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1978 | 60 | if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 1979 | 60 | limb_overflow_test_2 || limb_overflow_test_3) { | 1980 | 0 | self_reduce(); | 1981 | 0 | } | 1982 | 60 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE15reduction_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE15reduction_checkEv |
1983 | | |
1984 | | /** |
1985 | | * SANITY CHECK on a value that is about to interact with another value |
1986 | | * |
1987 | | * @details ASSERTs that the value of all limbs is less than or equal to the prohibited maximum value. Checks that the |
1988 | | *maximum value of the whole element is also less than a prohibited maximum value |
1989 | | * |
1990 | | **/ |
1991 | | template <typename Builder, typename T> void bigfield<Builder, T>::sanity_check() const |
1992 | 7.48M | { |
1993 | | |
1994 | 7.48M | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); |
1995 | 7.48M | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; |
1996 | 7.48M | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; |
1997 | 7.48M | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; |
1998 | 7.48M | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; |
1999 | 7.48M | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || |
2000 | 7.48M | limb_overflow_test_2 || limb_overflow_test_3)); |
2001 | 7.48M | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv Line | Count | Source | 1992 | 6.86M | { | 1993 | | | 1994 | 6.86M | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 6.86M | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 6.86M | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 6.86M | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 6.86M | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 6.86M | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 6.86M | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 6.86M | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv Line | Count | Source | 1992 | 1.51k | { | 1993 | | | 1994 | 1.51k | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 1.51k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 1.51k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 1.51k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 1.51k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 1.51k | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 1.51k | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 1.51k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv Line | Count | Source | 1992 | 64 | { | 1993 | | | 1994 | 64 | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 64 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 64 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 64 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 64 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 64 | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 64 | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 64 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12sanity_checkEv Line | Count | Source | 1992 | 24.9k | { | 1993 | | | 1994 | 24.9k | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 24.9k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 24.9k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 24.9k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 24.9k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 24.9k | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 24.9k | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 24.9k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12sanity_checkEv Line | Count | Source | 1992 | 278 | { | 1993 | | | 1994 | 278 | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 278 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 278 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 278 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 278 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 278 | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 278 | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 278 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12sanity_checkEv Line | Count | Source | 1992 | 545k | { | 1993 | | | 1994 | 545k | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 545k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 545k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 545k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 545k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 545k | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 545k | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 545k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12sanity_checkEv Line | Count | Source | 1992 | 5.18k | { | 1993 | | | 1994 | 5.18k | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 5.18k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 5.18k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 5.18k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 5.18k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 5.18k | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 5.18k | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 5.18k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12sanity_checkEv Line | Count | Source | 1992 | 40.9k | { | 1993 | | | 1994 | 40.9k | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 40.9k | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 40.9k | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 40.9k | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 40.9k | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 40.9k | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 40.9k | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 40.9k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12sanity_checkEv Line | Count | Source | 1992 | 170 | { | 1993 | | | 1994 | 170 | uint256_t maximum_limb_value = get_prohibited_maximum_limb_value(); | 1995 | 170 | bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value; | 1996 | 170 | bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value; | 1997 | 170 | bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value; | 1998 | 170 | bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value; | 1999 | 170 | ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 || | 2000 | 170 | limb_overflow_test_2 || limb_overflow_test_3)); | 2001 | 170 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12sanity_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12sanity_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv |
2002 | | |
2003 | | // Underneath performs assert_less_than(modulus) |
2004 | | // create a version with mod 2^t element part in [0,p-1] |
2005 | | // After reducing to size 2^s, we check (p-1)-a is non-negative as integer. |
2006 | | // We perform subtraction using carries on blocks of size 2^b. The operations inside the blocks are done mod r |
2007 | | // Including the effect of carries the operation inside each limb is in the range [-2^b-1,2^{b+1}] |
2008 | | // Assuming this values are all distinct mod r, which happens e.g. if r/2>2^{b+1}, then if all limb values are |
2009 | | // non-negative at the end of subtraction, we know the subtraction result is positive as integers and a<p |
2010 | | template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_in_field() const |
2011 | 509 | { |
2012 | 509 | assert_less_than(modulus); |
2013 | 509 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 16 | { | 2012 | 16 | assert_less_than(modulus); | 2013 | 16 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 3 | { | 2012 | 3 | assert_less_than(modulus); | 2013 | 3 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18assert_is_in_fieldEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 11 | { | 2012 | 11 | assert_less_than(modulus); | 2013 | 11 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 24 | { | 2012 | 24 | assert_less_than(modulus); | 2013 | 24 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 432 | { | 2012 | 432 | assert_less_than(modulus); | 2013 | 432 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 8 | { | 2012 | 8 | assert_less_than(modulus); | 2013 | 8 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv Line | Count | Source | 2011 | 15 | { | 2012 | 15 | assert_less_than(modulus); | 2013 | 15 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv |
2014 | | |
2015 | | template <typename Builder, typename T> void bigfield<Builder, T>::assert_less_than(const uint256_t upper_limit) const |
2016 | 676 | { |
2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced |
2018 | | // constants are allowed via ASSERT |
2019 | | |
2020 | 676 | if (is_constant()) { |
2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); |
2022 | 0 | return; |
2023 | 0 | } |
2024 | | |
2025 | 676 | ASSERT(upper_limit != 0); |
2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 |
2027 | | // from the limit |
2028 | 0 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); |
2029 | 0 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above |
2030 | 0 | uint256_t value = get_value().lo; |
2031 | |
|
2032 | 0 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); |
2033 | 0 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); |
2034 | 0 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); |
2035 | 0 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); |
2036 | |
|
2037 | 0 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; |
2038 | 0 | bool borrow_1_value = |
2039 | 0 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); |
2040 | 0 | bool borrow_2_value = |
2041 | 0 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); |
2042 | |
|
2043 | 0 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); |
2044 | 0 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); |
2045 | 0 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); |
2046 | 0 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); |
2047 | 0 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); |
2048 | 0 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); |
2049 | 0 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); |
2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. |
2051 | | // We check that the result in each limb is > 0. |
2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. |
2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are |
2054 | | // constrained. |
2055 | 0 | field_t<Builder> r0 = |
2056 | 0 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; |
2057 | 0 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + |
2058 | 0 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); |
2059 | 0 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + |
2060 | 0 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); |
2061 | 0 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); |
2062 | 0 | r0 = r0.normalize(); |
2063 | 0 | r1 = r1.normalize(); |
2064 | 0 | r2 = r2.normalize(); |
2065 | 0 | r3 = r3.normalize(); |
2066 | 676 | if constexpr (HasPlookup<Builder>) { |
2067 | 676 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); |
2068 | 676 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); |
2069 | 676 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); |
2070 | 676 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); |
2071 | 676 | } else { |
2072 | 0 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), |
2073 | 0 | static_cast<size_t>(NUM_LIMB_BITS), |
2074 | 0 | "bigfield: assert_less_than range constraint 1."); |
2075 | 0 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), |
2076 | 0 | static_cast<size_t>(NUM_LIMB_BITS), |
2077 | 0 | "bigfield: assert_less_than range constraint 2."); |
2078 | 0 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), |
2079 | 0 | static_cast<size_t>(NUM_LIMB_BITS), |
2080 | 0 | "bigfield: assert_less_than range constraint 3."); |
2081 | 0 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), |
2082 | 0 | static_cast<size_t>(NUM_LIMB_BITS), |
2083 | 0 | "bigfield: assert_less_than range constraint 4."); |
2084 | 0 | } |
2085 | 0 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 28 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 28 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 28 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 28 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 28 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 28 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 28 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 28 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 28 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 28 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 28 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 28 | bool borrow_1_value = | 2039 | 28 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 28 | bool borrow_2_value = | 2041 | 28 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 28 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 28 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 28 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 28 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 28 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 28 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 28 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 28 | field_t<Builder> r0 = | 2056 | 28 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 28 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 28 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 28 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 28 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 28 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 28 | r0 = r0.normalize(); | 2063 | 28 | r1 = r1.normalize(); | 2064 | 28 | r2 = r2.normalize(); | 2065 | 28 | r3 = r3.normalize(); | 2066 | 28 | if constexpr (HasPlookup<Builder>) { | 2067 | 28 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 28 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 28 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 28 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 28 | } else { | 2072 | 28 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 28 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 28 | "bigfield: assert_less_than range constraint 1."); | 2075 | 28 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 28 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 28 | "bigfield: assert_less_than range constraint 2."); | 2078 | 28 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 28 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 28 | "bigfield: assert_less_than range constraint 3."); | 2081 | 28 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 28 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 28 | "bigfield: assert_less_than range constraint 4."); | 2084 | 28 | } | 2085 | 28 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 3 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 3 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 3 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 3 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 3 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 3 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 3 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 3 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 3 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 3 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 3 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 3 | bool borrow_1_value = | 2039 | 3 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 3 | bool borrow_2_value = | 2041 | 3 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 3 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 3 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 3 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 3 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 3 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 3 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 3 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 3 | field_t<Builder> r0 = | 2056 | 3 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 3 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 3 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 3 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 3 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 3 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 3 | r0 = r0.normalize(); | 2063 | 3 | r1 = r1.normalize(); | 2064 | 3 | r2 = r2.normalize(); | 2065 | 3 | r3 = r3.normalize(); | 2066 | 3 | if constexpr (HasPlookup<Builder>) { | 2067 | 3 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 3 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 3 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 3 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 3 | } else { | 2072 | 3 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 3 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 3 | "bigfield: assert_less_than range constraint 1."); | 2075 | 3 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 3 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 3 | "bigfield: assert_less_than range constraint 2."); | 2078 | 3 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 3 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 3 | "bigfield: assert_less_than range constraint 3."); | 2081 | 3 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 3 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 3 | "bigfield: assert_less_than range constraint 4."); | 2084 | 3 | } | 2085 | 3 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 11 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 11 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 11 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 11 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 11 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 11 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 11 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 11 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 11 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 11 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 11 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 11 | bool borrow_1_value = | 2039 | 11 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 11 | bool borrow_2_value = | 2041 | 11 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 11 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 11 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 11 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 11 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 11 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 11 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 11 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 11 | field_t<Builder> r0 = | 2056 | 11 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 11 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 11 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 11 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 11 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 11 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 11 | r0 = r0.normalize(); | 2063 | 11 | r1 = r1.normalize(); | 2064 | 11 | r2 = r2.normalize(); | 2065 | 11 | r3 = r3.normalize(); | 2066 | 11 | if constexpr (HasPlookup<Builder>) { | 2067 | 11 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 11 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 11 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 11 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 11 | } else { | 2072 | 11 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 11 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 11 | "bigfield: assert_less_than range constraint 1."); | 2075 | 11 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 11 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 11 | "bigfield: assert_less_than range constraint 2."); | 2078 | 11 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 11 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 11 | "bigfield: assert_less_than range constraint 3."); | 2081 | 11 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 11 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 11 | "bigfield: assert_less_than range constraint 4."); | 2084 | 11 | } | 2085 | 11 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 30 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 30 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 30 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 30 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 30 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 30 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 30 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 30 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 30 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 30 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 30 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 30 | bool borrow_1_value = | 2039 | 30 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 30 | bool borrow_2_value = | 2041 | 30 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 30 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 30 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 30 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 30 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 30 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 30 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 30 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 30 | field_t<Builder> r0 = | 2056 | 30 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 30 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 30 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 30 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 30 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 30 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 30 | r0 = r0.normalize(); | 2063 | 30 | r1 = r1.normalize(); | 2064 | 30 | r2 = r2.normalize(); | 2065 | 30 | r3 = r3.normalize(); | 2066 | 30 | if constexpr (HasPlookup<Builder>) { | 2067 | 30 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 30 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 30 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 30 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 30 | } else { | 2072 | 30 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 30 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 30 | "bigfield: assert_less_than range constraint 1."); | 2075 | 30 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 30 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 30 | "bigfield: assert_less_than range constraint 2."); | 2078 | 30 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 30 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 30 | "bigfield: assert_less_than range constraint 3."); | 2081 | 30 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 30 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 30 | "bigfield: assert_less_than range constraint 4."); | 2084 | 30 | } | 2085 | 30 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 576 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 576 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 576 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 576 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 576 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 576 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 576 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 576 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 576 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 576 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 576 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 576 | bool borrow_1_value = | 2039 | 576 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 576 | bool borrow_2_value = | 2041 | 576 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 576 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 576 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 576 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 576 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 576 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 576 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 576 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 576 | field_t<Builder> r0 = | 2056 | 576 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 576 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 576 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 576 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 576 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 576 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 576 | r0 = r0.normalize(); | 2063 | 576 | r1 = r1.normalize(); | 2064 | 576 | r2 = r2.normalize(); | 2065 | 576 | r3 = r3.normalize(); | 2066 | 576 | if constexpr (HasPlookup<Builder>) { | 2067 | 576 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 576 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 576 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 576 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 576 | } else { | 2072 | 576 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 576 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 576 | "bigfield: assert_less_than range constraint 1."); | 2075 | 576 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 576 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 576 | "bigfield: assert_less_than range constraint 2."); | 2078 | 576 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 576 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 576 | "bigfield: assert_less_than range constraint 3."); | 2081 | 576 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 576 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 576 | "bigfield: assert_less_than range constraint 4."); | 2084 | 576 | } | 2085 | 576 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 8 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 8 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 8 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 8 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 8 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 8 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 8 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 8 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 8 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 8 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 8 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 8 | bool borrow_1_value = | 2039 | 8 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 8 | bool borrow_2_value = | 2041 | 8 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 8 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 8 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 8 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 8 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 8 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 8 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 8 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 8 | field_t<Builder> r0 = | 2056 | 8 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 8 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 8 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 8 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 8 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 8 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 8 | r0 = r0.normalize(); | 2063 | 8 | r1 = r1.normalize(); | 2064 | 8 | r2 = r2.normalize(); | 2065 | 8 | r3 = r3.normalize(); | 2066 | 8 | if constexpr (HasPlookup<Builder>) { | 2067 | 8 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 8 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 8 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 8 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 8 | } else { | 2072 | 8 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 8 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 8 | "bigfield: assert_less_than range constraint 1."); | 2075 | 8 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 8 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 8 | "bigfield: assert_less_than range constraint 2."); | 2078 | 8 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 8 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 8 | "bigfield: assert_less_than range constraint 3."); | 2081 | 8 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 8 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 8 | "bigfield: assert_less_than range constraint 4."); | 2084 | 8 | } | 2085 | 8 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Line | Count | Source | 2016 | 20 | { | 2017 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2018 | | // constants are allowed via ASSERT | 2019 | | | 2020 | 20 | if (is_constant()) { | 2021 | 0 | ASSERT(get_value() < static_cast<uint512_t>(upper_limit)); | 2022 | 0 | return; | 2023 | 0 | } | 2024 | | | 2025 | 20 | ASSERT(upper_limit != 0); | 2026 | | // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1 | 2027 | | // from the limit | 2028 | 20 | uint256_t strict_upper_limit = upper_limit - uint256_t(1); | 2029 | 20 | self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above | 2030 | 20 | uint256_t value = get_value().lo; | 2031 | | | 2032 | 20 | const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS); | 2033 | 20 | const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2); | 2034 | 20 | const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3); | 2035 | 20 | const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4); | 2036 | | | 2037 | 20 | bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0; | 2038 | 20 | bool borrow_1_value = | 2039 | 20 | (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1); | 2040 | 20 | bool borrow_2_value = | 2041 | 20 | (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2); | 2042 | | | 2043 | 20 | field_t<Builder> upper_limit_0(context, upper_limit_value_0); | 2044 | 20 | field_t<Builder> upper_limit_1(context, upper_limit_value_1); | 2045 | 20 | field_t<Builder> upper_limit_2(context, upper_limit_value_2); | 2046 | 20 | field_t<Builder> upper_limit_3(context, upper_limit_value_3); | 2047 | 20 | bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value)); | 2048 | 20 | bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value)); | 2049 | 20 | bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value)); | 2050 | | // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0. | 2051 | | // We check that the result in each limb is > 0. | 2052 | | // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb. | 2053 | | // The prover can rearrange the borrows the way they like. The important thing is that the borrows are | 2054 | | // constrained. | 2055 | 20 | field_t<Builder> r0 = | 2056 | 20 | upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1; | 2057 | 20 | field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element + | 2058 | 20 | static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0); | 2059 | 20 | field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element + | 2060 | 20 | static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1); | 2061 | 20 | field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2); | 2062 | 20 | r0 = r0.normalize(); | 2063 | 20 | r1 = r1.normalize(); | 2064 | 20 | r2 = r2.normalize(); | 2065 | 20 | r3 = r3.normalize(); | 2066 | 20 | if constexpr (HasPlookup<Builder>) { | 2067 | 20 | context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2068 | 20 | context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2069 | 20 | context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2070 | 20 | context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS)); | 2071 | 20 | } else { | 2072 | 20 | context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(), | 2073 | 20 | static_cast<size_t>(NUM_LIMB_BITS), | 2074 | 20 | "bigfield: assert_less_than range constraint 1."); | 2075 | 20 | context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(), | 2076 | 20 | static_cast<size_t>(NUM_LIMB_BITS), | 2077 | 20 | "bigfield: assert_less_than range constraint 2."); | 2078 | 20 | context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(), | 2079 | 20 | static_cast<size_t>(NUM_LIMB_BITS), | 2080 | 20 | "bigfield: assert_less_than range constraint 3."); | 2081 | 20 | context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(), | 2082 | 20 | static_cast<size_t>(NUM_LIMB_BITS), | 2083 | 20 | "bigfield: assert_less_than range constraint 4."); | 2084 | 20 | } | 2085 | 20 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE |
2086 | | |
2087 | | // check elements are equal mod p by proving their integer difference is a multiple of p. |
2088 | | // This relies on the minus operator for a-b increasing a by a multiple of p large enough so diff is non-negative |
2089 | | // When one of the elements is a constant and another is a witness we check equality of limbs, so if the witness |
2090 | | // bigfield element is in an unreduced form, it needs to be reduced first. We don't have automatice reduced form |
2091 | | // detection for now, so it is up to the circuit writer to detect this |
2092 | | template <typename Builder, typename T> void bigfield<Builder, T>::assert_equal(const bigfield& other) const |
2093 | 504 | { |
2094 | 504 | Builder* ctx = this->context ? this->context : other.context; |
2095 | | |
2096 | 504 | if (is_constant() && other.is_constant()) { |
2097 | 0 | std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl; |
2098 | 0 | ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus |
2099 | 0 | return; |
2100 | 504 | } else if (other.is_constant()) { |
2101 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here |
2102 | | // evaluate a strict equality - make sure *this is reduced first, or an honest prover |
2103 | | // might not be able to satisfy these constraints. |
2104 | 36 | field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element); |
2105 | 36 | field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element); |
2106 | 36 | field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element); |
2107 | 36 | field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element); |
2108 | 36 | field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb); |
2109 | 36 | t0.assert_is_zero(); |
2110 | 36 | t1.assert_is_zero(); |
2111 | 36 | t2.assert_is_zero(); |
2112 | 36 | t3.assert_is_zero(); |
2113 | 36 | t4.assert_is_zero(); |
2114 | 36 | return; |
2115 | 468 | } else if (is_constant()) { |
2116 | 0 | other.assert_equal(*this); |
2117 | 0 | return; |
2118 | 468 | } else { |
2119 | | |
2120 | 468 | bigfield diff = *this - other; |
2121 | 468 | const uint512_t diff_val = diff.get_value(); |
2122 | 468 | const uint512_t modulus(target_basis.modulus); |
2123 | | |
2124 | 468 | const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus); |
2125 | 468 | if (remainder_512 != 0) { |
2126 | 9 | std::cerr << "bigfield: remainder not zero!" << std::endl; |
2127 | 9 | } |
2128 | 468 | bigfield quotient; |
2129 | | |
2130 | 468 | const size_t num_quotient_bits = get_quotient_max_bits({ 0 }); |
2131 | 468 | quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)), |
2132 | 468 | witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)), |
2133 | 468 | false, |
2134 | 468 | num_quotient_bits); |
2135 | 468 | unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() }); |
2136 | 468 | } |
2137 | 504 | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_ Line | Count | Source | 2093 | 172 | { | 2094 | 172 | Builder* ctx = this->context ? this->context : other.context; | 2095 | | | 2096 | 172 | if (is_constant() && other.is_constant()) { | 2097 | 0 | std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl; | 2098 | 0 | ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus | 2099 | 0 | return; | 2100 | 172 | } else if (other.is_constant()) { | 2101 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here | 2102 | | // evaluate a strict equality - make sure *this is reduced first, or an honest prover | 2103 | | // might not be able to satisfy these constraints. | 2104 | 36 | field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element); | 2105 | 36 | field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element); | 2106 | 36 | field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element); | 2107 | 36 | field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element); | 2108 | 36 | field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb); | 2109 | 36 | t0.assert_is_zero(); | 2110 | 36 | t1.assert_is_zero(); | 2111 | 36 | t2.assert_is_zero(); | 2112 | 36 | t3.assert_is_zero(); | 2113 | 36 | t4.assert_is_zero(); | 2114 | 36 | return; | 2115 | 136 | } else if (is_constant()) { | 2116 | 0 | other.assert_equal(*this); | 2117 | 0 | return; | 2118 | 136 | } else { | 2119 | | | 2120 | 136 | bigfield diff = *this - other; | 2121 | 136 | const uint512_t diff_val = diff.get_value(); | 2122 | 136 | const uint512_t modulus(target_basis.modulus); | 2123 | | | 2124 | 136 | const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus); | 2125 | 136 | if (remainder_512 != 0) { | 2126 | 9 | std::cerr << "bigfield: remainder not zero!" << std::endl; | 2127 | 9 | } | 2128 | 136 | bigfield quotient; | 2129 | | | 2130 | 136 | const size_t num_quotient_bits = get_quotient_max_bits({ 0 }); | 2131 | 136 | quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)), | 2132 | 136 | witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)), | 2133 | 136 | false, | 2134 | 136 | num_quotient_bits); | 2135 | 136 | unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() }); | 2136 | 136 | } | 2137 | 172 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_ Line | Count | Source | 2093 | 322 | { | 2094 | 322 | Builder* ctx = this->context ? this->context : other.context; | 2095 | | | 2096 | 322 | if (is_constant() && other.is_constant()) { | 2097 | 0 | std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl; | 2098 | 0 | ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus | 2099 | 0 | return; | 2100 | 322 | } else if (other.is_constant()) { | 2101 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here | 2102 | | // evaluate a strict equality - make sure *this is reduced first, or an honest prover | 2103 | | // might not be able to satisfy these constraints. | 2104 | 0 | field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element); | 2105 | 0 | field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element); | 2106 | 0 | field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element); | 2107 | 0 | field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element); | 2108 | 0 | field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb); | 2109 | 0 | t0.assert_is_zero(); | 2110 | 0 | t1.assert_is_zero(); | 2111 | 0 | t2.assert_is_zero(); | 2112 | 0 | t3.assert_is_zero(); | 2113 | 0 | t4.assert_is_zero(); | 2114 | 0 | return; | 2115 | 322 | } else if (is_constant()) { | 2116 | 0 | other.assert_equal(*this); | 2117 | 0 | return; | 2118 | 322 | } else { | 2119 | | | 2120 | 322 | bigfield diff = *this - other; | 2121 | 322 | const uint512_t diff_val = diff.get_value(); | 2122 | 322 | const uint512_t modulus(target_basis.modulus); | 2123 | | | 2124 | 322 | const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus); | 2125 | 322 | if (remainder_512 != 0) { | 2126 | 0 | std::cerr << "bigfield: remainder not zero!" << std::endl; | 2127 | 0 | } | 2128 | 322 | bigfield quotient; | 2129 | | | 2130 | 322 | const size_t num_quotient_bits = get_quotient_max_bits({ 0 }); | 2131 | 322 | quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)), | 2132 | 322 | witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)), | 2133 | 322 | false, | 2134 | 322 | num_quotient_bits); | 2135 | 322 | unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() }); | 2136 | 322 | } | 2137 | 322 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12assert_equalERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12assert_equalERKS7_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12assert_equalERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12assert_equalERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12assert_equalERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12assert_equalERKS7_ Line | Count | Source | 2093 | 10 | { | 2094 | 10 | Builder* ctx = this->context ? this->context : other.context; | 2095 | | | 2096 | 10 | if (is_constant() && other.is_constant()) { | 2097 | 0 | std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl; | 2098 | 0 | ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus | 2099 | 0 | return; | 2100 | 10 | } else if (other.is_constant()) { | 2101 | | // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here | 2102 | | // evaluate a strict equality - make sure *this is reduced first, or an honest prover | 2103 | | // might not be able to satisfy these constraints. | 2104 | 0 | field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element); | 2105 | 0 | field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element); | 2106 | 0 | field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element); | 2107 | 0 | field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element); | 2108 | 0 | field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb); | 2109 | 0 | t0.assert_is_zero(); | 2110 | 0 | t1.assert_is_zero(); | 2111 | 0 | t2.assert_is_zero(); | 2112 | 0 | t3.assert_is_zero(); | 2113 | 0 | t4.assert_is_zero(); | 2114 | 0 | return; | 2115 | 10 | } else if (is_constant()) { | 2116 | 0 | other.assert_equal(*this); | 2117 | 0 | return; | 2118 | 10 | } else { | 2119 | | | 2120 | 10 | bigfield diff = *this - other; | 2121 | 10 | const uint512_t diff_val = diff.get_value(); | 2122 | 10 | const uint512_t modulus(target_basis.modulus); | 2123 | | | 2124 | 10 | const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus); | 2125 | 10 | if (remainder_512 != 0) { | 2126 | 0 | std::cerr << "bigfield: remainder not zero!" << std::endl; | 2127 | 0 | } | 2128 | 10 | bigfield quotient; | 2129 | | | 2130 | 10 | const size_t num_quotient_bits = get_quotient_max_bits({ 0 }); | 2131 | 10 | quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)), | 2132 | 10 | witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)), | 2133 | 10 | false, | 2134 | 10 | num_quotient_bits); | 2135 | 10 | unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() }); | 2136 | 10 | } | 2137 | 10 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12assert_equalERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12assert_equalERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_ |
2138 | | |
2139 | | // construct a proof that points are different mod p, when they are different mod r |
2140 | | // WARNING: This method doesn't have perfect completeness - for points equal mod r (or with certain difference kp |
2141 | | // mod r) but different mod p, you can't construct a proof. The chances of an honest prover running afoul of this |
2142 | | // condition are extremely small (TODO: compute probability) Note also that the number of constraints depends on how |
2143 | | // much the values have overflown beyond p e.g. due to an addition chain The function is based on the following. |
2144 | | // Suppose a-b = 0 mod p. Then a-b = k*p for k in a range [-R,L] such that L*p>= a, R*p>=b. And also a-b = k*p mod r |
2145 | | // for such k. Thus we can verify a-b is non-zero mod p by taking the product of such values (a-b-kp) and showing |
2146 | | // it's non-zero mod r |
2147 | | template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_not_equal(const bigfield& other) const |
2148 | 350k | { |
2149 | | // Why would we use this for 2 constants? Turns out, in biggroup |
2150 | 701k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { |
2151 | 701k | uint512_t target = target_modulus; |
2152 | 701k | size_t overload_count = 0; |
2153 | 1.40M | while (target <= maximum_value) { |
2154 | 701k | ++overload_count; |
2155 | 701k | target += target_modulus; |
2156 | 701k | } |
2157 | 701k | return overload_count; |
2158 | 701k | }; _ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_ Line | Count | Source | 2150 | 668k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 668k | uint512_t target = target_modulus; | 2152 | 668k | size_t overload_count = 0; | 2153 | 1.33M | while (target <= maximum_value) { | 2154 | 668k | ++overload_count; | 2155 | 668k | target += target_modulus; | 2156 | 668k | } | 2157 | 668k | return overload_count; | 2158 | 668k | }; |
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_ Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_ENKUlRKNS_7numeric5uintxINSB_9uint256_tEEEE_clESG_ Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_ _ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_ Line | Count | Source | 2150 | 1.22k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 1.22k | uint512_t target = target_modulus; | 2152 | 1.22k | size_t overload_count = 0; | 2153 | 2.44k | while (target <= maximum_value) { | 2154 | 1.22k | ++overload_count; | 2155 | 1.22k | target += target_modulus; | 2156 | 1.22k | } | 2157 | 1.22k | return overload_count; | 2158 | 1.22k | }; |
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_ Line | Count | Source | 2150 | 48 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 48 | uint512_t target = target_modulus; | 2152 | 48 | size_t overload_count = 0; | 2153 | 72 | while (target <= maximum_value) { | 2154 | 24 | ++overload_count; | 2155 | 24 | target += target_modulus; | 2156 | 24 | } | 2157 | 48 | return overload_count; | 2158 | 48 | }; |
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_ Line | Count | Source | 2150 | 28.5k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 28.5k | uint512_t target = target_modulus; | 2152 | 28.5k | size_t overload_count = 0; | 2153 | 57.0k | while (target <= maximum_value) { | 2154 | 28.5k | ++overload_count; | 2155 | 28.5k | target += target_modulus; | 2156 | 28.5k | } | 2157 | 28.5k | return overload_count; | 2158 | 28.5k | }; |
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_ Line | Count | Source | 2150 | 576 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 576 | uint512_t target = target_modulus; | 2152 | 576 | size_t overload_count = 0; | 2153 | 864 | while (target <= maximum_value) { | 2154 | 288 | ++overload_count; | 2155 | 288 | target += target_modulus; | 2156 | 288 | } | 2157 | 576 | return overload_count; | 2158 | 576 | }; |
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_ Line | Count | Source | 2150 | 2.57k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 2.57k | uint512_t target = target_modulus; | 2152 | 2.57k | size_t overload_count = 0; | 2153 | 5.13k | while (target <= maximum_value) { | 2154 | 2.56k | ++overload_count; | 2155 | 2.56k | target += target_modulus; | 2156 | 2.56k | } | 2157 | 2.57k | return overload_count; | 2158 | 2.57k | }; |
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_ Line | Count | Source | 2150 | 36 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 36 | uint512_t target = target_modulus; | 2152 | 36 | size_t overload_count = 0; | 2153 | 54 | while (target <= maximum_value) { | 2154 | 18 | ++overload_count; | 2155 | 18 | target += target_modulus; | 2156 | 18 | } | 2157 | 36 | return overload_count; | 2158 | 36 | }; |
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_ Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_ |
2159 | 350k | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); |
2160 | 350k | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); |
2161 | | |
2162 | | // if (a == b) then (a == b mod n) |
2163 | | // to save gates, we only check that (a == b mod n) |
2164 | | |
2165 | | // if numeric val of a = a' + p.q |
2166 | | // we want to check (a' + p.q == b mod n) |
2167 | 350k | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; |
2168 | 350k | auto diff = base_diff; |
2169 | 350k | field_t<Builder> prime_basis(get_context(), modulus); |
2170 | 350k | field_t<Builder> prime_basis_accumulator = prime_basis; |
2171 | | // Each loop iteration adds 1 gate |
2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) |
2173 | 706k | for (size_t i = 0; i < lhs_overload_count; ++i) { |
2174 | 355k | diff = diff * (base_diff - prime_basis_accumulator); |
2175 | 355k | prime_basis_accumulator += prime_basis; |
2176 | 355k | } |
2177 | 350k | prime_basis_accumulator = prime_basis; |
2178 | 695k | for (size_t i = 0; i < rhs_overload_count; ++i) { |
2179 | 345k | diff = diff * (base_diff + prime_basis_accumulator); |
2180 | 345k | prime_basis_accumulator += prime_basis; |
2181 | 345k | } |
2182 | 350k | diff.assert_is_not_zero(); |
2183 | 350k | } _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_ Line | Count | Source | 2148 | 334k | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 334k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 334k | uint512_t target = target_modulus; | 2152 | 334k | size_t overload_count = 0; | 2153 | 334k | while (target <= maximum_value) { | 2154 | 334k | ++overload_count; | 2155 | 334k | target += target_modulus; | 2156 | 334k | } | 2157 | 334k | return overload_count; | 2158 | 334k | }; | 2159 | 334k | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 334k | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 334k | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 334k | auto diff = base_diff; | 2169 | 334k | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 334k | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 673k | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 339k | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 339k | prime_basis_accumulator += prime_basis; | 2176 | 339k | } | 2177 | 334k | prime_basis_accumulator = prime_basis; | 2178 | 663k | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 329k | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 329k | prime_basis_accumulator += prime_basis; | 2181 | 329k | } | 2182 | 334k | diff.assert_is_not_zero(); | 2183 | 334k | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_ _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_ Line | Count | Source | 2148 | 610 | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 610 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 610 | uint512_t target = target_modulus; | 2152 | 610 | size_t overload_count = 0; | 2153 | 610 | while (target <= maximum_value) { | 2154 | 610 | ++overload_count; | 2155 | 610 | target += target_modulus; | 2156 | 610 | } | 2157 | 610 | return overload_count; | 2158 | 610 | }; | 2159 | 610 | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 610 | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 610 | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 610 | auto diff = base_diff; | 2169 | 610 | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 610 | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 1.22k | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 610 | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 610 | prime_basis_accumulator += prime_basis; | 2176 | 610 | } | 2177 | 610 | prime_basis_accumulator = prime_basis; | 2178 | 1.22k | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 610 | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 610 | prime_basis_accumulator += prime_basis; | 2181 | 610 | } | 2182 | 610 | diff.assert_is_not_zero(); | 2183 | 610 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_ Line | Count | Source | 2148 | 24 | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 24 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 24 | uint512_t target = target_modulus; | 2152 | 24 | size_t overload_count = 0; | 2153 | 24 | while (target <= maximum_value) { | 2154 | 24 | ++overload_count; | 2155 | 24 | target += target_modulus; | 2156 | 24 | } | 2157 | 24 | return overload_count; | 2158 | 24 | }; | 2159 | 24 | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 24 | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 24 | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 24 | auto diff = base_diff; | 2169 | 24 | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 24 | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 48 | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 24 | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 24 | prime_basis_accumulator += prime_basis; | 2176 | 24 | } | 2177 | 24 | prime_basis_accumulator = prime_basis; | 2178 | 24 | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 0 | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 0 | prime_basis_accumulator += prime_basis; | 2181 | 0 | } | 2182 | 24 | diff.assert_is_not_zero(); | 2183 | 24 | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_ Line | Count | Source | 2148 | 14.2k | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 14.2k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 14.2k | uint512_t target = target_modulus; | 2152 | 14.2k | size_t overload_count = 0; | 2153 | 14.2k | while (target <= maximum_value) { | 2154 | 14.2k | ++overload_count; | 2155 | 14.2k | target += target_modulus; | 2156 | 14.2k | } | 2157 | 14.2k | return overload_count; | 2158 | 14.2k | }; | 2159 | 14.2k | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 14.2k | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 14.2k | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 14.2k | auto diff = base_diff; | 2169 | 14.2k | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 14.2k | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 28.5k | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 14.2k | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 14.2k | prime_basis_accumulator += prime_basis; | 2176 | 14.2k | } | 2177 | 14.2k | prime_basis_accumulator = prime_basis; | 2178 | 28.5k | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 14.2k | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 14.2k | prime_basis_accumulator += prime_basis; | 2181 | 14.2k | } | 2182 | 14.2k | diff.assert_is_not_zero(); | 2183 | 14.2k | } |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_ Line | Count | Source | 2148 | 288 | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 288 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 288 | uint512_t target = target_modulus; | 2152 | 288 | size_t overload_count = 0; | 2153 | 288 | while (target <= maximum_value) { | 2154 | 288 | ++overload_count; | 2155 | 288 | target += target_modulus; | 2156 | 288 | } | 2157 | 288 | return overload_count; | 2158 | 288 | }; | 2159 | 288 | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 288 | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 288 | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 288 | auto diff = base_diff; | 2169 | 288 | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 288 | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 576 | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 288 | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 288 | prime_basis_accumulator += prime_basis; | 2176 | 288 | } | 2177 | 288 | prime_basis_accumulator = prime_basis; | 2178 | 288 | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 0 | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 0 | prime_basis_accumulator += prime_basis; | 2181 | 0 | } | 2182 | 288 | diff.assert_is_not_zero(); | 2183 | 288 | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_ Line | Count | Source | 2148 | 1.28k | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 1.28k | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 1.28k | uint512_t target = target_modulus; | 2152 | 1.28k | size_t overload_count = 0; | 2153 | 1.28k | while (target <= maximum_value) { | 2154 | 1.28k | ++overload_count; | 2155 | 1.28k | target += target_modulus; | 2156 | 1.28k | } | 2157 | 1.28k | return overload_count; | 2158 | 1.28k | }; | 2159 | 1.28k | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 1.28k | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 1.28k | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 1.28k | auto diff = base_diff; | 2169 | 1.28k | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 1.28k | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 2.56k | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 1.27k | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 1.27k | prime_basis_accumulator += prime_basis; | 2176 | 1.27k | } | 2177 | 1.28k | prime_basis_accumulator = prime_basis; | 2178 | 2.57k | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 1.28k | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 1.28k | prime_basis_accumulator += prime_basis; | 2181 | 1.28k | } | 2182 | 1.28k | diff.assert_is_not_zero(); | 2183 | 1.28k | } |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_ Line | Count | Source | 2148 | 18 | { | 2149 | | // Why would we use this for 2 constants? Turns out, in biggroup | 2150 | 18 | const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) { | 2151 | 18 | uint512_t target = target_modulus; | 2152 | 18 | size_t overload_count = 0; | 2153 | 18 | while (target <= maximum_value) { | 2154 | 18 | ++overload_count; | 2155 | 18 | target += target_modulus; | 2156 | 18 | } | 2157 | 18 | return overload_count; | 2158 | 18 | }; | 2159 | 18 | const size_t lhs_overload_count = get_overload_count(get_maximum_value()); | 2160 | 18 | const size_t rhs_overload_count = get_overload_count(other.get_maximum_value()); | 2161 | | | 2162 | | // if (a == b) then (a == b mod n) | 2163 | | // to save gates, we only check that (a == b mod n) | 2164 | | | 2165 | | // if numeric val of a = a' + p.q | 2166 | | // we want to check (a' + p.q == b mod n) | 2167 | 18 | const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb; | 2168 | 18 | auto diff = base_diff; | 2169 | 18 | field_t<Builder> prime_basis(get_context(), modulus); | 2170 | 18 | field_t<Builder> prime_basis_accumulator = prime_basis; | 2171 | | // Each loop iteration adds 1 gate | 2172 | | // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate) | 2173 | 36 | for (size_t i = 0; i < lhs_overload_count; ++i) { | 2174 | 18 | diff = diff * (base_diff - prime_basis_accumulator); | 2175 | 18 | prime_basis_accumulator += prime_basis; | 2176 | 18 | } | 2177 | 18 | prime_basis_accumulator = prime_basis; | 2178 | 18 | for (size_t i = 0; i < rhs_overload_count; ++i) { | 2179 | 0 | diff = diff * (base_diff + prime_basis_accumulator); | 2180 | 0 | prime_basis_accumulator += prime_basis; | 2181 | 0 | } | 2182 | 18 | diff.assert_is_not_zero(); | 2183 | 18 | } |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_ Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_ |
2184 | | |
2185 | | // We reduce an element's mod 2^t representation (t=4*NUM_LIMB_BITS) to size 2^s for smallest s with 2^s>p |
2186 | | // This is much cheaper than actually reducing mod p and suffices for addition chains (where we just need not to |
2187 | | // overflow 2^t) We also reduce any "spillage" inside the first 3 limbs, so that their range is NUM_LIMB_BITS and |
2188 | | // not larger |
2189 | | template <typename Builder, typename T> void bigfield<Builder, T>::self_reduce() const |
2190 | 2.05k | { |
2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced |
2192 | | // constants are disallowed via ASSERT |
2193 | 2.05k | if (is_constant()) { |
2194 | 1 | return; |
2195 | 1 | } |
2196 | 2.05k | OriginTag new_tag = get_origin_tag(); |
2197 | | // TODO: handle situation where some limbs are constant and others are not constant |
2198 | 2.05k | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); |
2199 | | |
2200 | 2.05k | bigfield quotient(context); |
2201 | | |
2202 | 2.05k | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; |
2203 | 2.05k | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; |
2204 | 2.05k | if ((maximum_quotient_bits & 1ULL) == 1ULL) { |
2205 | 1.35k | ++maximum_quotient_bits; |
2206 | 1.35k | } |
2207 | | |
2208 | 2.05k | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); |
2209 | 0 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); |
2210 | 0 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); |
2211 | 2.05k | if constexpr (HasPlookup<Builder>) { |
2212 | 2.05k | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), |
2213 | 2.05k | static_cast<size_t>(maximum_quotient_bits)); |
2214 | 2.05k | } else { |
2215 | 0 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), |
2216 | 0 | static_cast<size_t>(maximum_quotient_bits), |
2217 | 0 | "bigfield: quotient_limb too large."); |
2218 | 0 | } |
2219 | |
|
2220 | 2.05k | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < |
2221 | 0 | get_maximum_crt_product()); |
2222 | 0 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); |
2223 | 0 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); |
2224 | 0 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); |
2225 | 0 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); |
2226 | 0 | quotient.prime_basis_limb = quotient_limb; |
2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s |
2228 | 0 | bigfield remainder = bigfield( |
2229 | 0 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), |
2230 | 0 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); |
2231 | |
|
2232 | 0 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); |
2233 | 0 | binary_basis_limbs[0] = |
2234 | 0 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? |
2235 | 0 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; |
2236 | 0 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; |
2237 | 0 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; |
2238 | 0 | prime_basis_limb = remainder.prime_basis_limb; |
2239 | 0 | set_origin_tag(new_tag); |
2240 | 0 | } // namespace stdlib _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv Line | Count | Source | 2190 | 1.22k | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 1.22k | if (is_constant()) { | 2194 | 1 | return; | 2195 | 1 | } | 2196 | 1.22k | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 1.22k | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 1.22k | bigfield quotient(context); | 2201 | | | 2202 | 1.22k | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 1.22k | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 1.22k | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 533 | ++maximum_quotient_bits; | 2206 | 533 | } | 2207 | | | 2208 | 1.22k | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 1.22k | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 1.22k | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 1.22k | if constexpr (HasPlookup<Builder>) { | 2212 | 1.22k | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 1.22k | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 1.22k | } else { | 2215 | 1.22k | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 1.22k | static_cast<size_t>(maximum_quotient_bits), | 2217 | 1.22k | "bigfield: quotient_limb too large."); | 2218 | 1.22k | } | 2219 | | | 2220 | 1.22k | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 1.22k | get_maximum_crt_product()); | 2222 | 1.22k | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 1.22k | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 1.22k | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 1.22k | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 1.22k | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 1.22k | bigfield remainder = bigfield( | 2229 | 1.22k | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 1.22k | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 1.22k | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 1.22k | binary_basis_limbs[0] = | 2234 | 1.22k | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 1.22k | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 1.22k | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 1.22k | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 1.22k | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 1.22k | set_origin_tag(new_tag); | 2240 | 1.22k | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv Line | Count | Source | 2190 | 18 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 18 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 18 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 18 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 18 | bigfield quotient(context); | 2201 | | | 2202 | 18 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 18 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 18 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 13 | ++maximum_quotient_bits; | 2206 | 13 | } | 2207 | | | 2208 | 18 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 18 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 18 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 18 | if constexpr (HasPlookup<Builder>) { | 2212 | 18 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 18 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 18 | } else { | 2215 | 18 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 18 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 18 | "bigfield: quotient_limb too large."); | 2218 | 18 | } | 2219 | | | 2220 | 18 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 18 | get_maximum_crt_product()); | 2222 | 18 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 18 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 18 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 18 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 18 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 18 | bigfield remainder = bigfield( | 2229 | 18 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 18 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 18 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 18 | binary_basis_limbs[0] = | 2234 | 18 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 18 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 18 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 18 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 18 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 18 | set_origin_tag(new_tag); | 2240 | 18 | } // namespace stdlib |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE11self_reduceEv Line | Count | Source | 2190 | 22 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 22 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 22 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 22 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 22 | bigfield quotient(context); | 2201 | | | 2202 | 22 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 22 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 22 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 19 | ++maximum_quotient_bits; | 2206 | 19 | } | 2207 | | | 2208 | 22 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 22 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 22 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 22 | if constexpr (HasPlookup<Builder>) { | 2212 | 22 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 22 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 22 | } else { | 2215 | 22 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 22 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 22 | "bigfield: quotient_limb too large."); | 2218 | 22 | } | 2219 | | | 2220 | 22 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 22 | get_maximum_crt_product()); | 2222 | 22 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 22 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 22 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 22 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 22 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 22 | bigfield remainder = bigfield( | 2229 | 22 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 22 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 22 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 22 | binary_basis_limbs[0] = | 2234 | 22 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 22 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 22 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 22 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 22 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 22 | set_origin_tag(new_tag); | 2240 | 22 | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE11self_reduceEv Line | Count | Source | 2190 | 36 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 36 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 36 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 36 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 36 | bigfield quotient(context); | 2201 | | | 2202 | 36 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 36 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 36 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 33 | ++maximum_quotient_bits; | 2206 | 33 | } | 2207 | | | 2208 | 36 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 36 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 36 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 36 | if constexpr (HasPlookup<Builder>) { | 2212 | 36 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 36 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 36 | } else { | 2215 | 36 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 36 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 36 | "bigfield: quotient_limb too large."); | 2218 | 36 | } | 2219 | | | 2220 | 36 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 36 | get_maximum_crt_product()); | 2222 | 36 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 36 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 36 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 36 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 36 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 36 | bigfield remainder = bigfield( | 2229 | 36 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 36 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 36 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 36 | binary_basis_limbs[0] = | 2234 | 36 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 36 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 36 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 36 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 36 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 36 | set_origin_tag(new_tag); | 2240 | 36 | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE11self_reduceEv Line | Count | Source | 2190 | 144 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 144 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 144 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 144 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 144 | bigfield quotient(context); | 2201 | | | 2202 | 144 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 144 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 144 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 144 | ++maximum_quotient_bits; | 2206 | 144 | } | 2207 | | | 2208 | 144 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 144 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 144 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 144 | if constexpr (HasPlookup<Builder>) { | 2212 | 144 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 144 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 144 | } else { | 2215 | 144 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 144 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 144 | "bigfield: quotient_limb too large."); | 2218 | 144 | } | 2219 | | | 2220 | 144 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 144 | get_maximum_crt_product()); | 2222 | 144 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 144 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 144 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 144 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 144 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 144 | bigfield remainder = bigfield( | 2229 | 144 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 144 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 144 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 144 | binary_basis_limbs[0] = | 2234 | 144 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 144 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 144 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 144 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 144 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 144 | set_origin_tag(new_tag); | 2240 | 144 | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE11self_reduceEv Line | Count | Source | 2190 | 576 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 576 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 576 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 576 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 576 | bigfield quotient(context); | 2201 | | | 2202 | 576 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 576 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 576 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 576 | ++maximum_quotient_bits; | 2206 | 576 | } | 2207 | | | 2208 | 576 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 576 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 576 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 576 | if constexpr (HasPlookup<Builder>) { | 2212 | 576 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 576 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 576 | } else { | 2215 | 576 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 576 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 576 | "bigfield: quotient_limb too large."); | 2218 | 576 | } | 2219 | | | 2220 | 576 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 576 | get_maximum_crt_product()); | 2222 | 576 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 576 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 576 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 576 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 576 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 576 | bigfield remainder = bigfield( | 2229 | 576 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 576 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 576 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 576 | binary_basis_limbs[0] = | 2234 | 576 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 576 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 576 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 576 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 576 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 576 | set_origin_tag(new_tag); | 2240 | 576 | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE11self_reduceEv Line | Count | Source | 2190 | 13 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 13 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 13 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 13 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 13 | bigfield quotient(context); | 2201 | | | 2202 | 13 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 13 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 13 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 13 | ++maximum_quotient_bits; | 2206 | 13 | } | 2207 | | | 2208 | 13 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 13 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 13 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 13 | if constexpr (HasPlookup<Builder>) { | 2212 | 13 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 13 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 13 | } else { | 2215 | 13 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 13 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 13 | "bigfield: quotient_limb too large."); | 2218 | 13 | } | 2219 | | | 2220 | 13 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 13 | get_maximum_crt_product()); | 2222 | 13 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 13 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 13 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 13 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 13 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 13 | bigfield remainder = bigfield( | 2229 | 13 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 13 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 13 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 13 | binary_basis_limbs[0] = | 2234 | 13 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 13 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 13 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 13 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 13 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 13 | set_origin_tag(new_tag); | 2240 | 13 | } // namespace stdlib |
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE11self_reduceEv Line | Count | Source | 2190 | 20 | { | 2191 | | // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced | 2192 | | // constants are disallowed via ASSERT | 2193 | 20 | if (is_constant()) { | 2194 | 0 | return; | 2195 | 0 | } | 2196 | 20 | OriginTag new_tag = get_origin_tag(); | 2197 | | // TODO: handle situation where some limbs are constant and others are not constant | 2198 | 20 | const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus); | 2199 | | | 2200 | 20 | bigfield quotient(context); | 2201 | | | 2202 | 20 | uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus; | 2203 | 20 | uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1; | 2204 | 20 | if ((maximum_quotient_bits & 1ULL) == 1ULL) { | 2205 | 20 | ++maximum_quotient_bits; | 2206 | 20 | } | 2207 | | | 2208 | 20 | ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS); | 2209 | 20 | uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo)); | 2210 | 20 | field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index); | 2211 | 20 | if constexpr (HasPlookup<Builder>) { | 2212 | 20 | context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(), | 2213 | 20 | static_cast<size_t>(maximum_quotient_bits)); | 2214 | 20 | } else { | 2215 | 20 | context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(), | 2216 | 20 | static_cast<size_t>(maximum_quotient_bits), | 2217 | 20 | "bigfield: quotient_limb too large."); | 2218 | 20 | } | 2219 | | | 2220 | 20 | ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER < | 2221 | 20 | get_maximum_crt_product()); | 2222 | 20 | quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits); | 2223 | 20 | quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2224 | 20 | quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2225 | 20 | quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0); | 2226 | 20 | quotient.prime_basis_limb = quotient_limb; | 2227 | | // this constructor with can_overflow=false will enforce remainder of size<2^s | 2228 | 20 | bigfield remainder = bigfield( | 2229 | 20 | witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)), | 2230 | 20 | witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo))); | 2231 | | | 2232 | 20 | unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder }); | 2233 | 20 | binary_basis_limbs[0] = | 2234 | 20 | remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice? | 2235 | 20 | binary_basis_limbs[1] = remainder.binary_basis_limbs[1]; | 2236 | 20 | binary_basis_limbs[2] = remainder.binary_basis_limbs[2]; | 2237 | 20 | binary_basis_limbs[3] = remainder.binary_basis_limbs[3]; | 2238 | 20 | prime_basis_limb = remainder.prime_basis_limb; | 2239 | 20 | set_origin_tag(new_tag); | 2240 | 20 | } // namespace stdlib |
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv |
2241 | | |
2242 | | /** |
2243 | | * Evaluate a multiply add identity with several added elements and several remainders |
2244 | | * |
2245 | | * i.e: |
2246 | | * |
2247 | | * input_left*input_to_mul + (to_add[0]..to_add[-1]) - input_quotient*modulus - |
2248 | | * (input_remainders[0]+..+input_remainders[-1]) = 0 (mod CRT) |
2249 | | * |
2250 | | * See detailed explanation at https://hackmd.io/LoEG5nRHQe-PvstVaD51Yw?view |
2251 | | * |
2252 | | * THIS FUNCTION IS UNSAFE TO USE IN CIRCUITS AS IT DOES NOT PROTECT AGAINST CRT OVERFLOWS. |
2253 | | * */ |
2254 | | template <typename Builder, typename T> |
2255 | | void bigfield<Builder, T>::unsafe_evaluate_multiply_add(const bigfield& input_left, |
2256 | | const bigfield& input_to_mul, |
2257 | | const std::vector<bigfield>& to_add, |
2258 | | const bigfield& input_quotient, |
2259 | | const std::vector<bigfield>& input_remainders) |
2260 | 838k | { |
2261 | | |
2262 | 838k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
2263 | 838k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); |
2264 | | // Sanity checks |
2265 | 0 | input_left.sanity_check(); |
2266 | 0 | input_to_mul.sanity_check(); |
2267 | 0 | input_quotient.sanity_check(); |
2268 | 1.03M | for (auto& el : to_add) { |
2269 | 1.03M | el.sanity_check(); |
2270 | 1.03M | } |
2271 | 885k | for (auto& el : input_remainders) { |
2272 | 885k | el.sanity_check(); |
2273 | 885k | } |
2274 | |
|
2275 | 0 | std::vector<bigfield> remainders(input_remainders); |
2276 | |
|
2277 | 0 | bigfield left = input_left; |
2278 | 0 | bigfield to_mul = input_to_mul; |
2279 | 0 | bigfield quotient = input_quotient; |
2280 | |
|
2281 | 838k | Builder* ctx = left.context ? left.context : to_mul.context; |
2282 | |
|
2283 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); |
2284 | 0 | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); |
2285 | 0 | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); |
2286 | 0 | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); |
2287 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); |
2288 | 0 | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); |
2289 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); |
2290 | 0 | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); |
2291 | 0 | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); |
2292 | 0 | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); |
2293 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); |
2294 | 0 | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); |
2295 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); |
2296 | 0 | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); |
2297 | 0 | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); |
2298 | 0 | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); |
2299 | 0 | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); |
2300 | 0 | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); |
2301 | |
|
2302 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; |
2303 | 0 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); |
2304 | |
|
2305 | 0 | uint512_t max_r1 = max_b0 + max_b1; |
2306 | |
|
2307 | 0 | uint256_t borrow_lo_value = 0; |
2308 | 885k | for (const auto& remainder : input_remainders) { |
2309 | 885k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; |
2310 | 885k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; |
2311 | | |
2312 | 885k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + |
2313 | 885k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); |
2314 | 885k | } |
2315 | 0 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; |
2316 | 0 | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); |
2317 | |
|
2318 | 0 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; |
2319 | 0 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; |
2320 | |
|
2321 | 0 | uint512_t max_a0(0); |
2322 | 0 | uint512_t max_a1(0); |
2323 | 1.87M | for (size_t i = 0; i < to_add.size(); ++i) { |
2324 | 1.03M | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + |
2325 | 1.03M | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); |
2326 | 1.03M | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + |
2327 | 1.03M | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); |
2328 | 1.03M | } |
2329 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; |
2330 | 0 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); |
2331 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; |
2332 | |
|
2333 | 0 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); |
2334 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; |
2335 | 838k | if ((max_lo_bits & 1ULL) == 1ULL) { |
2336 | 212k | ++max_lo_bits; |
2337 | 212k | } |
2338 | 838k | if ((max_hi_bits & 1ULL) == 1ULL) { |
2339 | 569k | ++max_hi_bits; |
2340 | 569k | } |
2341 | |
|
2342 | 0 | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); |
2343 | 0 | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); |
2344 | |
|
2345 | 838k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { |
2346 | 0 | carry_lo_msb = 0; |
2347 | 0 | } |
2348 | 838k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { |
2349 | 0 | carry_hi_msb = 0; |
2350 | 0 | } |
2351 | 838k | if constexpr (HasPlookup<Builder>) { |
2352 | | // The plookup custom bigfield gate requires inputs are witnesses. |
2353 | | // If we're using constant values, instantiate them as circuit variables |
2354 | 838k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { |
2355 | 16.0k | bigfield output(input); |
2356 | 16.0k | output.prime_basis_limb = field_t<Builder>::from_witness_index( |
2357 | 16.0k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); |
2358 | 16.0k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( |
2359 | 16.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); |
2360 | 16.0k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( |
2361 | 16.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); |
2362 | 16.0k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( |
2363 | 16.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); |
2364 | 16.0k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( |
2365 | 16.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); |
2366 | 16.0k | output.context = ctx; |
2367 | 16.0k | return output; |
2368 | 16.0k | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_ Line | Count | Source | 2354 | 13.0k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 13.0k | bigfield output(input); | 2356 | 13.0k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 13.0k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 13.0k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 13.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 13.0k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 13.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 13.0k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 13.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 13.0k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 13.0k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 13.0k | output.context = ctx; | 2367 | 13.0k | return output; | 2368 | 13.0k | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_ Line | Count | Source | 2354 | 700 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 700 | bigfield output(input); | 2356 | 700 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 700 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 700 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 700 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 700 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 700 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 700 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 700 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 700 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 700 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 700 | output.context = ctx; | 2367 | 700 | return output; | 2368 | 700 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_ENKUlSA_E_clESA_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_ Line | Count | Source | 2354 | 70 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 70 | bigfield output(input); | 2356 | 70 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 70 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 70 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 70 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 70 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 70 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 70 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 70 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 70 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 70 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 70 | output.context = ctx; | 2367 | 70 | return output; | 2368 | 70 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_ Line | Count | Source | 2354 | 48 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 48 | bigfield output(input); | 2356 | 48 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 48 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 48 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 48 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 48 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 48 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 48 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 48 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 48 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 48 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 48 | output.context = ctx; | 2367 | 48 | return output; | 2368 | 48 | }; |
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_ Line | Count | Source | 2354 | 1.29k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 1.29k | bigfield output(input); | 2356 | 1.29k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 1.29k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 1.29k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 1.29k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 1.29k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 1.29k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 1.29k | output.context = ctx; | 2367 | 1.29k | return output; | 2368 | 1.29k | }; |
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_ Line | Count | Source | 2354 | 864 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 864 | bigfield output(input); | 2356 | 864 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 864 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 864 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 864 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 864 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 864 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 864 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 864 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 864 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 864 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 864 | output.context = ctx; | 2367 | 864 | return output; | 2368 | 864 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_ Line | Count | Source | 2354 | 23 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 23 | bigfield output(input); | 2356 | 23 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 23 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 23 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 23 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 23 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 23 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 23 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 23 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 23 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 23 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 23 | output.context = ctx; | 2367 | 23 | return output; | 2368 | 23 | }; |
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_ Line | Count | Source | 2354 | 40 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 40 | bigfield output(input); | 2356 | 40 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 40 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 40 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 40 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 40 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 40 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 40 | output.context = ctx; | 2367 | 40 | return output; | 2368 | 40 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_ |
2369 | 838k | if (left.is_constant()) { |
2370 | 6.16k | left = convert_constant_to_fixed_witness(left); |
2371 | 6.16k | } |
2372 | 838k | if (to_mul.is_constant()) { |
2373 | 4.61k | to_mul = convert_constant_to_fixed_witness(to_mul); |
2374 | 4.61k | } |
2375 | 838k | if (quotient.is_constant()) { |
2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); |
2377 | 0 | } |
2378 | 838k | if (remainders[0].is_constant()) { |
2379 | 5.31k | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); |
2380 | 5.31k | } |
2381 | | |
2382 | 838k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; |
2383 | 838k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; |
2384 | 838k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; |
2385 | 885k | for (size_t i = 1; i < remainders.size(); ++i) { |
2386 | 47.2k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); |
2387 | 47.2k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); |
2388 | 47.2k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); |
2389 | 47.2k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); |
2390 | 47.2k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); |
2391 | 47.2k | } |
2392 | 1.03M | for (const auto& add : to_add) { |
2393 | 1.03M | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); |
2394 | 1.03M | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); |
2395 | 1.03M | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); |
2396 | 1.03M | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); |
2397 | 1.03M | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); |
2398 | 1.03M | } |
2399 | | |
2400 | 838k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; |
2401 | 838k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; |
2402 | 838k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); |
2403 | 838k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); |
2404 | | |
2405 | 838k | if (needs_normalize) { |
2406 | 42.3k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); |
2407 | 42.3k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); |
2408 | 42.3k | } |
2409 | | |
2410 | 838k | field_t<Builder> remainder_limbs[4]{ |
2411 | 838k | field_t<Builder>::accumulate(limb_0_accumulator), |
2412 | 838k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
2413 | 838k | : remainders[0].binary_basis_limbs[1].element, |
2414 | 838k | field_t<Builder>::accumulate(limb_2_accumulator), |
2415 | 838k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
2416 | 838k | : remainders[0].binary_basis_limbs[3].element, |
2417 | 838k | }; |
2418 | 838k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); |
2419 | | |
2420 | 838k | bb::non_native_field_witnesses<bb::fr> witnesses{ |
2421 | 838k | { |
2422 | 838k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), |
2423 | 838k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), |
2424 | 838k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), |
2425 | 838k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), |
2426 | 838k | }, |
2427 | 838k | { |
2428 | 838k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), |
2429 | 838k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), |
2430 | 838k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), |
2431 | 838k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), |
2432 | 838k | }, |
2433 | 838k | { |
2434 | 838k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), |
2435 | 838k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), |
2436 | 838k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), |
2437 | 838k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), |
2438 | 838k | }, |
2439 | 838k | { |
2440 | 838k | remainder_limbs[0].get_normalized_witness_index(), |
2441 | 838k | remainder_limbs[1].get_normalized_witness_index(), |
2442 | 838k | remainder_limbs[2].get_normalized_witness_index(), |
2443 | 838k | remainder_limbs[3].get_normalized_witness_index(), |
2444 | 838k | }, |
2445 | 838k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, |
2446 | 838k | modulus, |
2447 | 838k | }; |
2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul |
2449 | 838k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); |
2450 | | |
2451 | 838k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); |
2452 | 838k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, |
2453 | 838k | to_mul.prime_basis_limb, |
2454 | 838k | quotient.prime_basis_limb * neg_prime, |
2455 | 838k | -remainder_prime_limb); |
2456 | | |
2457 | 838k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; |
2458 | 838k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); |
2459 | | |
2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom |
2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) |
2462 | 838k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { |
2463 | 34.5k | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), |
2464 | 34.5k | lo.get_normalized_witness_index(), |
2465 | 34.5k | size_t(carry_hi_msb), |
2466 | 34.5k | size_t(carry_lo_msb)); |
2467 | 803k | } else { |
2468 | 803k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); |
2469 | 803k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); |
2470 | 803k | } |
2471 | 838k | } else { |
2472 | 0 | const field_t b0 = left.binary_basis_limbs[1].element.madd( |
2473 | 0 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); |
2474 | 0 | const field_t b1 = left.binary_basis_limbs[0].element.madd( |
2475 | 0 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); |
2476 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( |
2477 | 0 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); |
2478 | 0 | const field_t c1 = left.binary_basis_limbs[2].element.madd( |
2479 | 0 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); |
2480 | 0 | const field_t c2 = left.binary_basis_limbs[0].element.madd( |
2481 | 0 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); |
2482 | 0 | const field_t d0 = left.binary_basis_limbs[3].element.madd( |
2483 | 0 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); |
2484 | 0 | const field_t d1 = left.binary_basis_limbs[2].element.madd( |
2485 | 0 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); |
2486 | 0 | const field_t d2 = left.binary_basis_limbs[1].element.madd( |
2487 | 0 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); |
2488 | 0 | const field_t d3 = left.binary_basis_limbs[0].element.madd( |
2489 | 0 | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); |
2490 | | |
2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb |
2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap |
2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion |
2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning |
2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are |
2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} |
2497 | |
|
2498 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( |
2499 | 0 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); |
2500 | |
|
2501 | 0 | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); |
2502 | 0 | const field_t r2 = c0.add_two(c1, c2); |
2503 | 0 | const field_t r3 = d0 + d1.add_two(d2, d3); |
2504 | |
|
2505 | 0 | field_t carry_lo_0 = r0 * shift_right_2; |
2506 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); |
2507 | 0 | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); |
2508 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); |
2509 | 0 | for (const auto& add_element : to_add) { |
2510 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, |
2511 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); |
2512 | 0 | } |
2513 | 0 | for (size_t i = 1; i < remainders.size(); ++i) { |
2514 | 0 | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, |
2515 | 0 | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); |
2516 | 0 | } |
2517 | 0 | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, |
2518 | 0 | -(remainders[0].binary_basis_limbs[3].element * shift_1)); |
2519 | 0 | carry_lo += borrow_lo; |
2520 | 0 | field_t carry_hi_0 = r2 * shift_right_2; |
2521 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); |
2522 | 0 | field_t carry_hi_2 = t1 * shift_right_2; |
2523 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); |
2524 | |
|
2525 | 0 | for (const auto& add_element : to_add) { |
2526 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, |
2527 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); |
2528 | 0 | } |
2529 | 0 | for (size_t i = 1; i < remainders.size(); ++i) { |
2530 | 0 | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, |
2531 | 0 | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); |
2532 | 0 | } |
2533 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); |
2534 | |
|
2535 | 0 | field_t<Builder> linear_terms(ctx, bb::fr(0)); |
2536 | 0 | if (to_add.size() >= 2) { |
2537 | 0 | for (size_t i = 0; i < to_add.size(); i += 2) { |
2538 | 0 | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); |
2539 | 0 | } |
2540 | 0 | } |
2541 | 0 | if ((to_add.size() & 1UL) == 1UL) { |
2542 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; |
2543 | 0 | } |
2544 | 0 | if (remainders.size() >= 2) { |
2545 | 0 | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { |
2546 | 0 | linear_terms = |
2547 | 0 | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); |
2548 | 0 | } |
2549 | 0 | } |
2550 | 0 | if ((remainders.size() & 1UL) == 1UL) { |
2551 | 0 | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; |
2552 | 0 | } |
2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) |
2554 | 0 | field_t<Builder>::evaluate_polynomial_identity( |
2555 | 0 | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); |
2556 | |
|
2557 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); |
2558 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { |
2559 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); |
2560 | 0 | carry_combined = carry_combined.normalize(); |
2561 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( |
2562 | 0 | carry_combined.get_normalized_witness_index(), |
2563 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), |
2564 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); |
2565 | 0 | field_t<Builder> accumulator_midpoint = |
2566 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); |
2567 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); |
2568 | 0 | } else { |
2569 | 0 | carry_lo = carry_lo.normalize(); |
2570 | 0 | carry_hi = carry_hi.normalize(); |
2571 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), |
2572 | 0 | static_cast<size_t>(carry_lo_msb), |
2573 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); |
2574 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), |
2575 | 0 | static_cast<size_t>(carry_hi_msb), |
2576 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); |
2577 | 0 | } |
2578 | 0 | } |
2579 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ Line | Count | Source | 2260 | 772k | { | 2261 | | | 2262 | 772k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 772k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 772k | input_left.sanity_check(); | 2266 | 772k | input_to_mul.sanity_check(); | 2267 | 772k | input_quotient.sanity_check(); | 2268 | 947k | for (auto& el : to_add) { | 2269 | 947k | el.sanity_check(); | 2270 | 947k | } | 2271 | 819k | for (auto& el : input_remainders) { | 2272 | 819k | el.sanity_check(); | 2273 | 819k | } | 2274 | | | 2275 | 772k | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 772k | bigfield left = input_left; | 2278 | 772k | bigfield to_mul = input_to_mul; | 2279 | 772k | bigfield quotient = input_quotient; | 2280 | | | 2281 | 772k | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 772k | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 772k | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 772k | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 772k | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 772k | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 772k | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 772k | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 772k | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 772k | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 772k | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 772k | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 772k | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 772k | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 772k | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 772k | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 772k | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 772k | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 772k | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 772k | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 772k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 772k | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 772k | uint256_t borrow_lo_value = 0; | 2308 | 819k | for (const auto& remainder : input_remainders) { | 2309 | 819k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 819k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 819k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 819k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 819k | } | 2315 | 772k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 772k | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 772k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 772k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 772k | uint512_t max_a0(0); | 2322 | 772k | uint512_t max_a1(0); | 2323 | 1.71M | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 947k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 947k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 947k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 947k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 947k | } | 2329 | 772k | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 772k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 772k | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 772k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 772k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 772k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 184k | ++max_lo_bits; | 2337 | 184k | } | 2338 | 772k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 566k | ++max_hi_bits; | 2340 | 566k | } | 2341 | | | 2342 | 772k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 772k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 772k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 772k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 772k | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 772k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 772k | bigfield output(input); | 2356 | 772k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 772k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 772k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 772k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 772k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 772k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 772k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 772k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 772k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 772k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 772k | output.context = ctx; | 2367 | 772k | return output; | 2368 | 772k | }; | 2369 | 772k | if (left.is_constant()) { | 2370 | 6.16k | left = convert_constant_to_fixed_witness(left); | 2371 | 6.16k | } | 2372 | 772k | if (to_mul.is_constant()) { | 2373 | 1.91k | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 1.91k | } | 2375 | 772k | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 772k | if (remainders[0].is_constant()) { | 2379 | 4.97k | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 4.97k | } | 2381 | | | 2382 | 772k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 772k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 772k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 819k | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 47.0k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 47.0k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 47.0k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 47.0k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 47.0k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 47.0k | } | 2392 | 947k | for (const auto& add : to_add) { | 2393 | 947k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 947k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 947k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 947k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 947k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 947k | } | 2399 | | | 2400 | 772k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 772k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 772k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 772k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 772k | if (needs_normalize) { | 2406 | 37.0k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 37.0k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 37.0k | } | 2409 | | | 2410 | 772k | field_t<Builder> remainder_limbs[4]{ | 2411 | 772k | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 772k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 772k | : remainders[0].binary_basis_limbs[1].element, | 2414 | 772k | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 772k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 772k | : remainders[0].binary_basis_limbs[3].element, | 2417 | 772k | }; | 2418 | 772k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 772k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 772k | { | 2422 | 772k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 772k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 772k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 772k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 772k | }, | 2427 | 772k | { | 2428 | 772k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 772k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 772k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 772k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 772k | }, | 2433 | 772k | { | 2434 | 772k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 772k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 772k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 772k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 772k | }, | 2439 | 772k | { | 2440 | 772k | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 772k | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 772k | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 772k | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 772k | }, | 2445 | 772k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 772k | modulus, | 2447 | 772k | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 772k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 772k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 772k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 772k | to_mul.prime_basis_limb, | 2454 | 772k | quotient.prime_basis_limb * neg_prime, | 2455 | 772k | -remainder_prime_limb); | 2456 | | | 2457 | 772k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 772k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 772k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 8.33k | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 8.33k | lo.get_normalized_witness_index(), | 2465 | 8.33k | size_t(carry_hi_msb), | 2466 | 8.33k | size_t(carry_lo_msb)); | 2467 | 763k | } else { | 2468 | 763k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 763k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 763k | } | 2471 | 772k | } else { | 2472 | 772k | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 772k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 772k | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 772k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 772k | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 772k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 772k | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 772k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 772k | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 772k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 772k | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 772k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 772k | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 772k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 772k | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 772k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 772k | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 772k | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 772k | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 772k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 772k | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 772k | const field_t r2 = c0.add_two(c1, c2); | 2503 | 772k | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 772k | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 772k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 772k | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 772k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 772k | for (const auto& add_element : to_add) { | 2510 | 772k | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 772k | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 772k | } | 2513 | 772k | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 772k | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 772k | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 772k | } | 2517 | 772k | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 772k | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 772k | carry_lo += borrow_lo; | 2520 | 772k | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 772k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 772k | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 772k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 772k | for (const auto& add_element : to_add) { | 2526 | 772k | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 772k | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 772k | } | 2529 | 772k | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 772k | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 772k | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 772k | } | 2533 | 772k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 772k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 772k | if (to_add.size() >= 2) { | 2537 | 772k | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 772k | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 772k | } | 2540 | 772k | } | 2541 | 772k | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 772k | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 772k | } | 2544 | 772k | if (remainders.size() >= 2) { | 2545 | 772k | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 772k | linear_terms = | 2547 | 772k | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 772k | } | 2549 | 772k | } | 2550 | 772k | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 772k | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 772k | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 772k | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 772k | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 772k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 772k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 772k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 772k | carry_combined = carry_combined.normalize(); | 2561 | 772k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 772k | carry_combined.get_normalized_witness_index(), | 2563 | 772k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 772k | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 772k | field_t<Builder> accumulator_midpoint = | 2566 | 772k | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 772k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 772k | } else { | 2569 | 772k | carry_lo = carry_lo.normalize(); | 2570 | 772k | carry_hi = carry_hi.normalize(); | 2571 | 772k | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 772k | static_cast<size_t>(carry_lo_msb), | 2573 | 772k | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 772k | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 772k | static_cast<size_t>(carry_hi_msb), | 2576 | 772k | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 772k | } | 2578 | 772k | } | 2579 | 772k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ Line | Count | Source | 2260 | 378 | { | 2261 | | | 2262 | 378 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 378 | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 378 | input_left.sanity_check(); | 2266 | 378 | input_to_mul.sanity_check(); | 2267 | 378 | input_quotient.sanity_check(); | 2268 | 378 | for (auto& el : to_add) { | 2269 | 0 | el.sanity_check(); | 2270 | 0 | } | 2271 | 378 | for (auto& el : input_remainders) { | 2272 | 378 | el.sanity_check(); | 2273 | 378 | } | 2274 | | | 2275 | 378 | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 378 | bigfield left = input_left; | 2278 | 378 | bigfield to_mul = input_to_mul; | 2279 | 378 | bigfield quotient = input_quotient; | 2280 | | | 2281 | 378 | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 378 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 378 | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 378 | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 378 | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 378 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 378 | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 378 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 378 | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 378 | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 378 | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 378 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 378 | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 378 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 378 | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 378 | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 378 | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 378 | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 378 | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 378 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 378 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 378 | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 378 | uint256_t borrow_lo_value = 0; | 2308 | 378 | for (const auto& remainder : input_remainders) { | 2309 | 378 | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 378 | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 378 | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 378 | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 378 | } | 2315 | 378 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 378 | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 378 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 378 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 378 | uint512_t max_a0(0); | 2322 | 378 | uint512_t max_a1(0); | 2323 | 378 | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 0 | } | 2329 | 378 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 378 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 378 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 378 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 378 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 378 | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 330 | ++max_lo_bits; | 2337 | 330 | } | 2338 | 378 | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 8 | ++max_hi_bits; | 2340 | 8 | } | 2341 | | | 2342 | 378 | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 378 | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 378 | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 378 | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 378 | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 378 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 378 | bigfield output(input); | 2356 | 378 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 378 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 378 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 378 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 378 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 378 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 378 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 378 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 378 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 378 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 378 | output.context = ctx; | 2367 | 378 | return output; | 2368 | 378 | }; | 2369 | 378 | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 378 | if (to_mul.is_constant()) { | 2373 | 378 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 378 | } | 2375 | 378 | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 378 | if (remainders[0].is_constant()) { | 2379 | 322 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 322 | } | 2381 | | | 2382 | 378 | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 378 | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 378 | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 378 | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 0 | } | 2392 | 378 | for (const auto& add : to_add) { | 2393 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 0 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 0 | } | 2399 | | | 2400 | 378 | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 378 | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 378 | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 378 | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 378 | if (needs_normalize) { | 2406 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 0 | } | 2409 | | | 2410 | 378 | field_t<Builder> remainder_limbs[4]{ | 2411 | 378 | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 378 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 378 | : remainders[0].binary_basis_limbs[1].element, | 2414 | 378 | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 378 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 378 | : remainders[0].binary_basis_limbs[3].element, | 2417 | 378 | }; | 2418 | 378 | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 378 | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 378 | { | 2422 | 378 | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 378 | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 378 | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 378 | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 378 | }, | 2427 | 378 | { | 2428 | 378 | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 378 | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 378 | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 378 | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 378 | }, | 2433 | 378 | { | 2434 | 378 | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 378 | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 378 | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 378 | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 378 | }, | 2439 | 378 | { | 2440 | 378 | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 378 | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 378 | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 378 | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 378 | }, | 2445 | 378 | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 378 | modulus, | 2447 | 378 | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 378 | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 378 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 378 | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 378 | to_mul.prime_basis_limb, | 2454 | 378 | quotient.prime_basis_limb * neg_prime, | 2455 | 378 | -remainder_prime_limb); | 2456 | | | 2457 | 378 | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 378 | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 378 | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 370 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 370 | lo.get_normalized_witness_index(), | 2465 | 370 | size_t(carry_hi_msb), | 2466 | 370 | size_t(carry_lo_msb)); | 2467 | 370 | } else { | 2468 | 8 | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 8 | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 8 | } | 2471 | 378 | } else { | 2472 | 378 | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 378 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 378 | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 378 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 378 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 378 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 378 | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 378 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 378 | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 378 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 378 | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 378 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 378 | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 378 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 378 | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 378 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 378 | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 378 | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 378 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 378 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 378 | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 378 | const field_t r2 = c0.add_two(c1, c2); | 2503 | 378 | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 378 | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 378 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 378 | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 378 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 378 | for (const auto& add_element : to_add) { | 2510 | 378 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 378 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 378 | } | 2513 | 378 | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 378 | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 378 | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 378 | } | 2517 | 378 | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 378 | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 378 | carry_lo += borrow_lo; | 2520 | 378 | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 378 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 378 | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 378 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 378 | for (const auto& add_element : to_add) { | 2526 | 378 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 378 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 378 | } | 2529 | 378 | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 378 | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 378 | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 378 | } | 2533 | 378 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 378 | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 378 | if (to_add.size() >= 2) { | 2537 | 378 | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 378 | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 378 | } | 2540 | 378 | } | 2541 | 378 | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 378 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 378 | } | 2544 | 378 | if (remainders.size() >= 2) { | 2545 | 378 | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 378 | linear_terms = | 2547 | 378 | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 378 | } | 2549 | 378 | } | 2550 | 378 | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 378 | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 378 | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 378 | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 378 | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 378 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 378 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 378 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 378 | carry_combined = carry_combined.normalize(); | 2561 | 378 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 378 | carry_combined.get_normalized_witness_index(), | 2563 | 378 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 378 | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 378 | field_t<Builder> accumulator_midpoint = | 2566 | 378 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 378 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 378 | } else { | 2569 | 378 | carry_lo = carry_lo.normalize(); | 2570 | 378 | carry_hi = carry_hi.normalize(); | 2571 | 378 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 378 | static_cast<size_t>(carry_lo_msb), | 2573 | 378 | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 378 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 378 | static_cast<size_t>(carry_hi_msb), | 2576 | 378 | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 378 | } | 2578 | 378 | } | 2579 | 378 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_ Line | Count | Source | 2260 | 16 | { | 2261 | | | 2262 | 16 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 16 | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 16 | input_left.sanity_check(); | 2266 | 16 | input_to_mul.sanity_check(); | 2267 | 16 | input_quotient.sanity_check(); | 2268 | 16 | for (auto& el : to_add) { | 2269 | 0 | el.sanity_check(); | 2270 | 0 | } | 2271 | 16 | for (auto& el : input_remainders) { | 2272 | 16 | el.sanity_check(); | 2273 | 16 | } | 2274 | | | 2275 | 16 | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 16 | bigfield left = input_left; | 2278 | 16 | bigfield to_mul = input_to_mul; | 2279 | 16 | bigfield quotient = input_quotient; | 2280 | | | 2281 | 16 | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 16 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 16 | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 16 | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 16 | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 16 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 16 | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 16 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 16 | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 16 | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 16 | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 16 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 16 | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 16 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 16 | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 16 | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 16 | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 16 | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 16 | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 16 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 16 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 16 | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 16 | uint256_t borrow_lo_value = 0; | 2308 | 16 | for (const auto& remainder : input_remainders) { | 2309 | 16 | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 16 | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 16 | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 16 | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 16 | } | 2315 | 16 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 16 | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 16 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 16 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 16 | uint512_t max_a0(0); | 2322 | 16 | uint512_t max_a1(0); | 2323 | 16 | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 0 | } | 2329 | 16 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 16 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 16 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 16 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 16 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 16 | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 0 | ++max_lo_bits; | 2337 | 0 | } | 2338 | 16 | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 16 | ++max_hi_bits; | 2340 | 16 | } | 2341 | | | 2342 | 16 | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 16 | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 16 | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 16 | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 16 | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 16 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 16 | bigfield output(input); | 2356 | 16 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 16 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 16 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 16 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 16 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 16 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 16 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 16 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 16 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 16 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 16 | output.context = ctx; | 2367 | 16 | return output; | 2368 | 16 | }; | 2369 | 16 | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 16 | if (to_mul.is_constant()) { | 2373 | 0 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 0 | } | 2375 | 16 | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 16 | if (remainders[0].is_constant()) { | 2379 | 0 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 0 | } | 2381 | | | 2382 | 16 | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 16 | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 16 | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 16 | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 0 | } | 2392 | 16 | for (const auto& add : to_add) { | 2393 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 0 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 0 | } | 2399 | | | 2400 | 16 | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 16 | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 16 | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 16 | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 16 | if (needs_normalize) { | 2406 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 0 | } | 2409 | | | 2410 | 16 | field_t<Builder> remainder_limbs[4]{ | 2411 | 16 | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 16 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 16 | : remainders[0].binary_basis_limbs[1].element, | 2414 | 16 | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 16 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 16 | : remainders[0].binary_basis_limbs[3].element, | 2417 | 16 | }; | 2418 | 16 | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 16 | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 16 | { | 2422 | 16 | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 16 | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 16 | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 16 | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 16 | }, | 2427 | 16 | { | 2428 | 16 | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 16 | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 16 | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 16 | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 16 | }, | 2433 | 16 | { | 2434 | 16 | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 16 | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 16 | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 16 | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 16 | }, | 2439 | 16 | { | 2440 | 16 | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 16 | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 16 | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 16 | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 16 | }, | 2445 | 16 | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 16 | modulus, | 2447 | 16 | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 16 | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 16 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 16 | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 16 | to_mul.prime_basis_limb, | 2454 | 16 | quotient.prime_basis_limb * neg_prime, | 2455 | 16 | -remainder_prime_limb); | 2456 | | | 2457 | 16 | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 16 | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 16 | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 0 | lo.get_normalized_witness_index(), | 2465 | 0 | size_t(carry_hi_msb), | 2466 | 0 | size_t(carry_lo_msb)); | 2467 | 16 | } else { | 2468 | 16 | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 16 | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 16 | } | 2471 | 16 | } else { | 2472 | 16 | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 16 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 16 | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 16 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 16 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 16 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 16 | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 16 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 16 | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 16 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 16 | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 16 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 16 | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 16 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 16 | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 16 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 16 | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 16 | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 16 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 16 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 16 | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 16 | const field_t r2 = c0.add_two(c1, c2); | 2503 | 16 | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 16 | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 16 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 16 | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 16 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 16 | for (const auto& add_element : to_add) { | 2510 | 16 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 16 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 16 | } | 2513 | 16 | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 16 | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 16 | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 16 | } | 2517 | 16 | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 16 | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 16 | carry_lo += borrow_lo; | 2520 | 16 | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 16 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 16 | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 16 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 16 | for (const auto& add_element : to_add) { | 2526 | 16 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 16 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 16 | } | 2529 | 16 | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 16 | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 16 | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 16 | } | 2533 | 16 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 16 | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 16 | if (to_add.size() >= 2) { | 2537 | 16 | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 16 | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 16 | } | 2540 | 16 | } | 2541 | 16 | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 16 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 16 | } | 2544 | 16 | if (remainders.size() >= 2) { | 2545 | 16 | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 16 | linear_terms = | 2547 | 16 | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 16 | } | 2549 | 16 | } | 2550 | 16 | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 16 | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 16 | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 16 | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 16 | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 16 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 16 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 16 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 16 | carry_combined = carry_combined.normalize(); | 2561 | 16 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 16 | carry_combined.get_normalized_witness_index(), | 2563 | 16 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 16 | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 16 | field_t<Builder> accumulator_midpoint = | 2566 | 16 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 16 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 16 | } else { | 2569 | 16 | carry_lo = carry_lo.normalize(); | 2570 | 16 | carry_hi = carry_hi.normalize(); | 2571 | 16 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 16 | static_cast<size_t>(carry_lo_msb), | 2573 | 16 | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 16 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 16 | static_cast<size_t>(carry_hi_msb), | 2576 | 16 | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 16 | } | 2578 | 16 | } | 2579 | 16 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ Line | Count | Source | 2260 | 2.74k | { | 2261 | | | 2262 | 2.74k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 2.74k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 2.74k | input_left.sanity_check(); | 2266 | 2.74k | input_to_mul.sanity_check(); | 2267 | 2.74k | input_quotient.sanity_check(); | 2268 | 3.73k | for (auto& el : to_add) { | 2269 | 3.73k | el.sanity_check(); | 2270 | 3.73k | } | 2271 | 2.74k | for (auto& el : input_remainders) { | 2272 | 2.74k | el.sanity_check(); | 2273 | 2.74k | } | 2274 | | | 2275 | 2.74k | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 2.74k | bigfield left = input_left; | 2278 | 2.74k | bigfield to_mul = input_to_mul; | 2279 | 2.74k | bigfield quotient = input_quotient; | 2280 | | | 2281 | 2.74k | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 2.74k | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 2.74k | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 2.74k | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 2.74k | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 2.74k | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 2.74k | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 2.74k | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 2.74k | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 2.74k | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 2.74k | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 2.74k | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 2.74k | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 2.74k | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 2.74k | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 2.74k | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 2.74k | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 2.74k | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 2.74k | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 2.74k | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 2.74k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 2.74k | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 2.74k | uint256_t borrow_lo_value = 0; | 2308 | 2.74k | for (const auto& remainder : input_remainders) { | 2309 | 2.74k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 2.74k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 2.74k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 2.74k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 2.74k | } | 2315 | 2.74k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 2.74k | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 2.74k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 2.74k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 2.74k | uint512_t max_a0(0); | 2322 | 2.74k | uint512_t max_a1(0); | 2323 | 6.47k | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 3.73k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 3.73k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 3.73k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 3.73k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 3.73k | } | 2329 | 2.74k | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 2.74k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 2.74k | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 2.74k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 2.74k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 2.74k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 1.22k | ++max_lo_bits; | 2337 | 1.22k | } | 2338 | 2.74k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 40 | ++max_hi_bits; | 2340 | 40 | } | 2341 | | | 2342 | 2.74k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 2.74k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 2.74k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 2.74k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 2.74k | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 2.74k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 2.74k | bigfield output(input); | 2356 | 2.74k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 2.74k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 2.74k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 2.74k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 2.74k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 2.74k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 2.74k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 2.74k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 2.74k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 2.74k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 2.74k | output.context = ctx; | 2367 | 2.74k | return output; | 2368 | 2.74k | }; | 2369 | 2.74k | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 2.74k | if (to_mul.is_constant()) { | 2373 | 70 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 70 | } | 2375 | 2.74k | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 2.74k | if (remainders[0].is_constant()) { | 2379 | 0 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 0 | } | 2381 | | | 2382 | 2.74k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 2.74k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 2.74k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 2.74k | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 6 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 6 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 6 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 6 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 6 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 6 | } | 2392 | 3.73k | for (const auto& add : to_add) { | 2393 | 3.73k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 3.73k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 3.73k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 3.73k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 3.73k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 3.73k | } | 2399 | | | 2400 | 2.74k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 2.74k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 2.74k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 2.74k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 2.74k | if (needs_normalize) { | 2406 | 214 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 214 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 214 | } | 2409 | | | 2410 | 2.74k | field_t<Builder> remainder_limbs[4]{ | 2411 | 2.74k | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 2.74k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 2.74k | : remainders[0].binary_basis_limbs[1].element, | 2414 | 2.74k | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 2.74k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 2.74k | : remainders[0].binary_basis_limbs[3].element, | 2417 | 2.74k | }; | 2418 | 2.74k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 2.74k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 2.74k | { | 2422 | 2.74k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 2.74k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 2.74k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 2.74k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 2.74k | }, | 2427 | 2.74k | { | 2428 | 2.74k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 2.74k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 2.74k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 2.74k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 2.74k | }, | 2433 | 2.74k | { | 2434 | 2.74k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 2.74k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 2.74k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 2.74k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 2.74k | }, | 2439 | 2.74k | { | 2440 | 2.74k | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 2.74k | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 2.74k | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 2.74k | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 2.74k | }, | 2445 | 2.74k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 2.74k | modulus, | 2447 | 2.74k | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 2.74k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 2.74k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 2.74k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 2.74k | to_mul.prime_basis_limb, | 2454 | 2.74k | quotient.prime_basis_limb * neg_prime, | 2455 | 2.74k | -remainder_prime_limb); | 2456 | | | 2457 | 2.74k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 2.74k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 2.74k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 1.13k | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 1.13k | lo.get_normalized_witness_index(), | 2465 | 1.13k | size_t(carry_hi_msb), | 2466 | 1.13k | size_t(carry_lo_msb)); | 2467 | 1.61k | } else { | 2468 | 1.61k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 1.61k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 1.61k | } | 2471 | 2.74k | } else { | 2472 | 2.74k | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 2.74k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 2.74k | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 2.74k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 2.74k | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 2.74k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 2.74k | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 2.74k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 2.74k | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 2.74k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 2.74k | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 2.74k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 2.74k | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 2.74k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 2.74k | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 2.74k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 2.74k | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 2.74k | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 2.74k | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 2.74k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 2.74k | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 2.74k | const field_t r2 = c0.add_two(c1, c2); | 2503 | 2.74k | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 2.74k | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 2.74k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 2.74k | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 2.74k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 2.74k | for (const auto& add_element : to_add) { | 2510 | 2.74k | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 2.74k | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 2.74k | } | 2513 | 2.74k | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 2.74k | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 2.74k | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 2.74k | } | 2517 | 2.74k | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 2.74k | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 2.74k | carry_lo += borrow_lo; | 2520 | 2.74k | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 2.74k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 2.74k | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 2.74k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 2.74k | for (const auto& add_element : to_add) { | 2526 | 2.74k | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 2.74k | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 2.74k | } | 2529 | 2.74k | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 2.74k | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 2.74k | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 2.74k | } | 2533 | 2.74k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 2.74k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 2.74k | if (to_add.size() >= 2) { | 2537 | 2.74k | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 2.74k | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 2.74k | } | 2540 | 2.74k | } | 2541 | 2.74k | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 2.74k | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 2.74k | } | 2544 | 2.74k | if (remainders.size() >= 2) { | 2545 | 2.74k | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 2.74k | linear_terms = | 2547 | 2.74k | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 2.74k | } | 2549 | 2.74k | } | 2550 | 2.74k | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 2.74k | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 2.74k | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 2.74k | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 2.74k | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 2.74k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 2.74k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 2.74k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 2.74k | carry_combined = carry_combined.normalize(); | 2561 | 2.74k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 2.74k | carry_combined.get_normalized_witness_index(), | 2563 | 2.74k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 2.74k | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 2.74k | field_t<Builder> accumulator_midpoint = | 2566 | 2.74k | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 2.74k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 2.74k | } else { | 2569 | 2.74k | carry_lo = carry_lo.normalize(); | 2570 | 2.74k | carry_hi = carry_hi.normalize(); | 2571 | 2.74k | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 2.74k | static_cast<size_t>(carry_lo_msb), | 2573 | 2.74k | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 2.74k | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 2.74k | static_cast<size_t>(carry_hi_msb), | 2576 | 2.74k | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 2.74k | } | 2578 | 2.74k | } | 2579 | 2.74k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ Line | Count | Source | 2260 | 63 | { | 2261 | | | 2262 | 63 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 63 | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 63 | input_left.sanity_check(); | 2266 | 63 | input_to_mul.sanity_check(); | 2267 | 63 | input_quotient.sanity_check(); | 2268 | 63 | for (auto& el : to_add) { | 2269 | 26 | el.sanity_check(); | 2270 | 26 | } | 2271 | 63 | for (auto& el : input_remainders) { | 2272 | 63 | el.sanity_check(); | 2273 | 63 | } | 2274 | | | 2275 | 63 | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 63 | bigfield left = input_left; | 2278 | 63 | bigfield to_mul = input_to_mul; | 2279 | 63 | bigfield quotient = input_quotient; | 2280 | | | 2281 | 63 | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 63 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 63 | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 63 | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 63 | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 63 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 63 | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 63 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 63 | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 63 | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 63 | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 63 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 63 | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 63 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 63 | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 63 | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 63 | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 63 | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 63 | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 63 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 63 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 63 | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 63 | uint256_t borrow_lo_value = 0; | 2308 | 63 | for (const auto& remainder : input_remainders) { | 2309 | 63 | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 63 | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 63 | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 63 | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 63 | } | 2315 | 63 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 63 | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 63 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 63 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 63 | uint512_t max_a0(0); | 2322 | 63 | uint512_t max_a1(0); | 2323 | 89 | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 26 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 26 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 26 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 26 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 26 | } | 2329 | 63 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 63 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 63 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 63 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 63 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 63 | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 3 | ++max_lo_bits; | 2337 | 3 | } | 2338 | 63 | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 12 | ++max_hi_bits; | 2340 | 12 | } | 2341 | | | 2342 | 63 | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 63 | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 63 | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 63 | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 63 | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 63 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 63 | bigfield output(input); | 2356 | 63 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 63 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 63 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 63 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 63 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 63 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 63 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 63 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 63 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 63 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 63 | output.context = ctx; | 2367 | 63 | return output; | 2368 | 63 | }; | 2369 | 63 | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 63 | if (to_mul.is_constant()) { | 2373 | 48 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 48 | } | 2375 | 63 | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 63 | if (remainders[0].is_constant()) { | 2379 | 0 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 0 | } | 2381 | | | 2382 | 63 | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 63 | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 63 | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 63 | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 0 | } | 2392 | 63 | for (const auto& add : to_add) { | 2393 | 26 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 26 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 26 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 26 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 26 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 26 | } | 2399 | | | 2400 | 63 | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 63 | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 63 | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 63 | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 63 | if (needs_normalize) { | 2406 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 0 | } | 2409 | | | 2410 | 63 | field_t<Builder> remainder_limbs[4]{ | 2411 | 63 | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 63 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 63 | : remainders[0].binary_basis_limbs[1].element, | 2414 | 63 | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 63 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 63 | : remainders[0].binary_basis_limbs[3].element, | 2417 | 63 | }; | 2418 | 63 | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 63 | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 63 | { | 2422 | 63 | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 63 | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 63 | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 63 | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 63 | }, | 2427 | 63 | { | 2428 | 63 | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 63 | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 63 | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 63 | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 63 | }, | 2433 | 63 | { | 2434 | 63 | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 63 | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 63 | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 63 | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 63 | }, | 2439 | 63 | { | 2440 | 63 | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 63 | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 63 | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 63 | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 63 | }, | 2445 | 63 | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 63 | modulus, | 2447 | 63 | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 63 | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 63 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 63 | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 63 | to_mul.prime_basis_limb, | 2454 | 63 | quotient.prime_basis_limb * neg_prime, | 2455 | 63 | -remainder_prime_limb); | 2456 | | | 2457 | 63 | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 63 | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 63 | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 50 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 50 | lo.get_normalized_witness_index(), | 2465 | 50 | size_t(carry_hi_msb), | 2466 | 50 | size_t(carry_lo_msb)); | 2467 | 50 | } else { | 2468 | 13 | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 13 | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 13 | } | 2471 | 63 | } else { | 2472 | 63 | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 63 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 63 | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 63 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 63 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 63 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 63 | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 63 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 63 | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 63 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 63 | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 63 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 63 | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 63 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 63 | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 63 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 63 | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 63 | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 63 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 63 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 63 | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 63 | const field_t r2 = c0.add_two(c1, c2); | 2503 | 63 | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 63 | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 63 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 63 | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 63 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 63 | for (const auto& add_element : to_add) { | 2510 | 63 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 63 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 63 | } | 2513 | 63 | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 63 | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 63 | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 63 | } | 2517 | 63 | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 63 | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 63 | carry_lo += borrow_lo; | 2520 | 63 | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 63 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 63 | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 63 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 63 | for (const auto& add_element : to_add) { | 2526 | 63 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 63 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 63 | } | 2529 | 63 | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 63 | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 63 | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 63 | } | 2533 | 63 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 63 | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 63 | if (to_add.size() >= 2) { | 2537 | 63 | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 63 | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 63 | } | 2540 | 63 | } | 2541 | 63 | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 63 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 63 | } | 2544 | 63 | if (remainders.size() >= 2) { | 2545 | 63 | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 63 | linear_terms = | 2547 | 63 | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 63 | } | 2549 | 63 | } | 2550 | 63 | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 63 | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 63 | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 63 | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 63 | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 63 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 63 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 63 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 63 | carry_combined = carry_combined.normalize(); | 2561 | 63 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 63 | carry_combined.get_normalized_witness_index(), | 2563 | 63 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 63 | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 63 | field_t<Builder> accumulator_midpoint = | 2566 | 63 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 63 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 63 | } else { | 2569 | 63 | carry_lo = carry_lo.normalize(); | 2570 | 63 | carry_hi = carry_hi.normalize(); | 2571 | 63 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 63 | static_cast<size_t>(carry_lo_msb), | 2573 | 63 | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 63 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 63 | static_cast<size_t>(carry_hi_msb), | 2576 | 63 | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 63 | } | 2578 | 63 | } | 2579 | 63 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ Line | Count | Source | 2260 | 58.1k | { | 2261 | | | 2262 | 58.1k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 58.1k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 58.1k | input_left.sanity_check(); | 2266 | 58.1k | input_to_mul.sanity_check(); | 2267 | 58.1k | input_quotient.sanity_check(); | 2268 | 81.5k | for (auto& el : to_add) { | 2269 | 81.5k | el.sanity_check(); | 2270 | 81.5k | } | 2271 | 58.3k | for (auto& el : input_remainders) { | 2272 | 58.3k | el.sanity_check(); | 2273 | 58.3k | } | 2274 | | | 2275 | 58.1k | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 58.1k | bigfield left = input_left; | 2278 | 58.1k | bigfield to_mul = input_to_mul; | 2279 | 58.1k | bigfield quotient = input_quotient; | 2280 | | | 2281 | 58.1k | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 58.1k | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 58.1k | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 58.1k | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 58.1k | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 58.1k | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 58.1k | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 58.1k | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 58.1k | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 58.1k | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 58.1k | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 58.1k | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 58.1k | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 58.1k | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 58.1k | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 58.1k | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 58.1k | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 58.1k | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 58.1k | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 58.1k | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 58.1k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 58.1k | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 58.1k | uint256_t borrow_lo_value = 0; | 2308 | 58.3k | for (const auto& remainder : input_remainders) { | 2309 | 58.3k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 58.3k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 58.3k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 58.3k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 58.3k | } | 2315 | 58.1k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 58.1k | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 58.1k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 58.1k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 58.1k | uint512_t max_a0(0); | 2322 | 58.1k | uint512_t max_a1(0); | 2323 | 139k | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 81.5k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 81.5k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 81.5k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 81.5k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 81.5k | } | 2329 | 58.1k | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 58.1k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 58.1k | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 58.1k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 58.1k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 58.1k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 25.7k | ++max_lo_bits; | 2337 | 25.7k | } | 2338 | 58.1k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 576 | ++max_hi_bits; | 2340 | 576 | } | 2341 | | | 2342 | 58.1k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 58.1k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 58.1k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 58.1k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 58.1k | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 58.1k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 58.1k | bigfield output(input); | 2356 | 58.1k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 58.1k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 58.1k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 58.1k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 58.1k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 58.1k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 58.1k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 58.1k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 58.1k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 58.1k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 58.1k | output.context = ctx; | 2367 | 58.1k | return output; | 2368 | 58.1k | }; | 2369 | 58.1k | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 58.1k | if (to_mul.is_constant()) { | 2373 | 1.29k | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 1.29k | } | 2375 | 58.1k | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 58.1k | if (remainders[0].is_constant()) { | 2379 | 0 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 0 | } | 2381 | | | 2382 | 58.1k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 58.1k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 58.1k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 58.3k | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 144 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 144 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 144 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 144 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 144 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 144 | } | 2392 | 81.5k | for (const auto& add : to_add) { | 2393 | 81.5k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 81.5k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 81.5k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 81.5k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 81.5k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 81.5k | } | 2399 | | | 2400 | 58.1k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 58.1k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 58.1k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 58.1k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 58.1k | if (needs_normalize) { | 2406 | 4.75k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 4.75k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 4.75k | } | 2409 | | | 2410 | 58.1k | field_t<Builder> remainder_limbs[4]{ | 2411 | 58.1k | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 58.1k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 58.1k | : remainders[0].binary_basis_limbs[1].element, | 2414 | 58.1k | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 58.1k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 58.1k | : remainders[0].binary_basis_limbs[3].element, | 2417 | 58.1k | }; | 2418 | 58.1k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 58.1k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 58.1k | { | 2422 | 58.1k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 58.1k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 58.1k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 58.1k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 58.1k | }, | 2427 | 58.1k | { | 2428 | 58.1k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 58.1k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 58.1k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 58.1k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 58.1k | }, | 2433 | 58.1k | { | 2434 | 58.1k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 58.1k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 58.1k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 58.1k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 58.1k | }, | 2439 | 58.1k | { | 2440 | 58.1k | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 58.1k | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 58.1k | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 58.1k | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 58.1k | }, | 2445 | 58.1k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 58.1k | modulus, | 2447 | 58.1k | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 58.1k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 58.1k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 58.1k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 58.1k | to_mul.prime_basis_limb, | 2454 | 58.1k | quotient.prime_basis_limb * neg_prime, | 2455 | 58.1k | -remainder_prime_limb); | 2456 | | | 2457 | 58.1k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 58.1k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 58.1k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 23.7k | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 23.7k | lo.get_normalized_witness_index(), | 2465 | 23.7k | size_t(carry_hi_msb), | 2466 | 23.7k | size_t(carry_lo_msb)); | 2467 | 34.4k | } else { | 2468 | 34.4k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 34.4k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 34.4k | } | 2471 | 58.1k | } else { | 2472 | 58.1k | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 58.1k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 58.1k | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 58.1k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 58.1k | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 58.1k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 58.1k | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 58.1k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 58.1k | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 58.1k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 58.1k | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 58.1k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 58.1k | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 58.1k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 58.1k | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 58.1k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 58.1k | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 58.1k | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 58.1k | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 58.1k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 58.1k | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 58.1k | const field_t r2 = c0.add_two(c1, c2); | 2503 | 58.1k | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 58.1k | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 58.1k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 58.1k | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 58.1k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 58.1k | for (const auto& add_element : to_add) { | 2510 | 58.1k | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 58.1k | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 58.1k | } | 2513 | 58.1k | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 58.1k | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 58.1k | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 58.1k | } | 2517 | 58.1k | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 58.1k | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 58.1k | carry_lo += borrow_lo; | 2520 | 58.1k | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 58.1k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 58.1k | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 58.1k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 58.1k | for (const auto& add_element : to_add) { | 2526 | 58.1k | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 58.1k | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 58.1k | } | 2529 | 58.1k | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 58.1k | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 58.1k | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 58.1k | } | 2533 | 58.1k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 58.1k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 58.1k | if (to_add.size() >= 2) { | 2537 | 58.1k | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 58.1k | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 58.1k | } | 2540 | 58.1k | } | 2541 | 58.1k | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 58.1k | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 58.1k | } | 2544 | 58.1k | if (remainders.size() >= 2) { | 2545 | 58.1k | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 58.1k | linear_terms = | 2547 | 58.1k | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 58.1k | } | 2549 | 58.1k | } | 2550 | 58.1k | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 58.1k | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 58.1k | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 58.1k | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 58.1k | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 58.1k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 58.1k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 58.1k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 58.1k | carry_combined = carry_combined.normalize(); | 2561 | 58.1k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 58.1k | carry_combined.get_normalized_witness_index(), | 2563 | 58.1k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 58.1k | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 58.1k | field_t<Builder> accumulator_midpoint = | 2566 | 58.1k | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 58.1k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 58.1k | } else { | 2569 | 58.1k | carry_lo = carry_lo.normalize(); | 2570 | 58.1k | carry_hi = carry_hi.normalize(); | 2571 | 58.1k | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 58.1k | static_cast<size_t>(carry_lo_msb), | 2573 | 58.1k | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 58.1k | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 58.1k | static_cast<size_t>(carry_hi_msb), | 2576 | 58.1k | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 58.1k | } | 2578 | 58.1k | } | 2579 | 58.1k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ Line | Count | Source | 2260 | 1.15k | { | 2261 | | | 2262 | 1.15k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 1.15k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 1.15k | input_left.sanity_check(); | 2266 | 1.15k | input_to_mul.sanity_check(); | 2267 | 1.15k | input_quotient.sanity_check(); | 2268 | 1.15k | for (auto& el : to_add) { | 2269 | 576 | el.sanity_check(); | 2270 | 576 | } | 2271 | 1.15k | for (auto& el : input_remainders) { | 2272 | 1.15k | el.sanity_check(); | 2273 | 1.15k | } | 2274 | | | 2275 | 1.15k | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 1.15k | bigfield left = input_left; | 2278 | 1.15k | bigfield to_mul = input_to_mul; | 2279 | 1.15k | bigfield quotient = input_quotient; | 2280 | | | 2281 | 1.15k | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 1.15k | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 1.15k | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 1.15k | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 1.15k | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 1.15k | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 1.15k | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 1.15k | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 1.15k | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 1.15k | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 1.15k | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 1.15k | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 1.15k | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 1.15k | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 1.15k | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 1.15k | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 1.15k | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 1.15k | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 1.15k | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 1.15k | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 1.15k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 1.15k | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 1.15k | uint256_t borrow_lo_value = 0; | 2308 | 1.15k | for (const auto& remainder : input_remainders) { | 2309 | 1.15k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 1.15k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 1.15k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 1.15k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 1.15k | } | 2315 | 1.15k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 1.15k | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 1.15k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 1.15k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 1.15k | uint512_t max_a0(0); | 2322 | 1.15k | uint512_t max_a1(0); | 2323 | 1.72k | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 576 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 576 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 576 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 576 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 576 | } | 2329 | 1.15k | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 1.15k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 1.15k | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 1.15k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 1.15k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 1.15k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 0 | ++max_lo_bits; | 2337 | 0 | } | 2338 | 1.15k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 288 | ++max_hi_bits; | 2340 | 288 | } | 2341 | | | 2342 | 1.15k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 1.15k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 1.15k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 1.15k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 1.15k | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 1.15k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 1.15k | bigfield output(input); | 2356 | 1.15k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 1.15k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 1.15k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 1.15k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 1.15k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 1.15k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 1.15k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 1.15k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 1.15k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 1.15k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 1.15k | output.context = ctx; | 2367 | 1.15k | return output; | 2368 | 1.15k | }; | 2369 | 1.15k | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 1.15k | if (to_mul.is_constant()) { | 2373 | 864 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 864 | } | 2375 | 1.15k | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 1.15k | if (remainders[0].is_constant()) { | 2379 | 0 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 0 | } | 2381 | | | 2382 | 1.15k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 1.15k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 1.15k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 1.15k | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 0 | } | 2392 | 1.15k | for (const auto& add : to_add) { | 2393 | 576 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 576 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 576 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 576 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 576 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 576 | } | 2399 | | | 2400 | 1.15k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 1.15k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 1.15k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 1.15k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 1.15k | if (needs_normalize) { | 2406 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 0 | } | 2409 | | | 2410 | 1.15k | field_t<Builder> remainder_limbs[4]{ | 2411 | 1.15k | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 1.15k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 1.15k | : remainders[0].binary_basis_limbs[1].element, | 2414 | 1.15k | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 1.15k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 1.15k | : remainders[0].binary_basis_limbs[3].element, | 2417 | 1.15k | }; | 2418 | 1.15k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 1.15k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 1.15k | { | 2422 | 1.15k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 1.15k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 1.15k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 1.15k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 1.15k | }, | 2427 | 1.15k | { | 2428 | 1.15k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 1.15k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 1.15k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 1.15k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 1.15k | }, | 2433 | 1.15k | { | 2434 | 1.15k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 1.15k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 1.15k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 1.15k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 1.15k | }, | 2439 | 1.15k | { | 2440 | 1.15k | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 1.15k | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 1.15k | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 1.15k | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 1.15k | }, | 2445 | 1.15k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 1.15k | modulus, | 2447 | 1.15k | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 1.15k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 1.15k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 1.15k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 1.15k | to_mul.prime_basis_limb, | 2454 | 1.15k | quotient.prime_basis_limb * neg_prime, | 2455 | 1.15k | -remainder_prime_limb); | 2456 | | | 2457 | 1.15k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 1.15k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 1.15k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 864 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 864 | lo.get_normalized_witness_index(), | 2465 | 864 | size_t(carry_hi_msb), | 2466 | 864 | size_t(carry_lo_msb)); | 2467 | 864 | } else { | 2468 | 288 | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 288 | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 288 | } | 2471 | 1.15k | } else { | 2472 | 1.15k | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 1.15k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 1.15k | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 1.15k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 1.15k | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 1.15k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 1.15k | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 1.15k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 1.15k | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 1.15k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 1.15k | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 1.15k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 1.15k | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 1.15k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 1.15k | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 1.15k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 1.15k | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 1.15k | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 1.15k | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 1.15k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 1.15k | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 1.15k | const field_t r2 = c0.add_two(c1, c2); | 2503 | 1.15k | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 1.15k | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 1.15k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 1.15k | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 1.15k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 1.15k | for (const auto& add_element : to_add) { | 2510 | 1.15k | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 1.15k | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 1.15k | } | 2513 | 1.15k | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 1.15k | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 1.15k | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 1.15k | } | 2517 | 1.15k | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 1.15k | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 1.15k | carry_lo += borrow_lo; | 2520 | 1.15k | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 1.15k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 1.15k | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 1.15k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 1.15k | for (const auto& add_element : to_add) { | 2526 | 1.15k | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 1.15k | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 1.15k | } | 2529 | 1.15k | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 1.15k | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 1.15k | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 1.15k | } | 2533 | 1.15k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 1.15k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 1.15k | if (to_add.size() >= 2) { | 2537 | 1.15k | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 1.15k | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 1.15k | } | 2540 | 1.15k | } | 2541 | 1.15k | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 1.15k | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 1.15k | } | 2544 | 1.15k | if (remainders.size() >= 2) { | 2545 | 1.15k | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 1.15k | linear_terms = | 2547 | 1.15k | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 1.15k | } | 2549 | 1.15k | } | 2550 | 1.15k | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 1.15k | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 1.15k | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 1.15k | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 1.15k | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 1.15k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 1.15k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 1.15k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 1.15k | carry_combined = carry_combined.normalize(); | 2561 | 1.15k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 1.15k | carry_combined.get_normalized_witness_index(), | 2563 | 1.15k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 1.15k | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 1.15k | field_t<Builder> accumulator_midpoint = | 2566 | 1.15k | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 1.15k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 1.15k | } else { | 2569 | 1.15k | carry_lo = carry_lo.normalize(); | 2570 | 1.15k | carry_hi = carry_hi.normalize(); | 2571 | 1.15k | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 1.15k | static_cast<size_t>(carry_lo_msb), | 2573 | 1.15k | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 1.15k | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 1.15k | static_cast<size_t>(carry_hi_msb), | 2576 | 1.15k | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 1.15k | } | 2578 | 1.15k | } | 2579 | 1.15k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ Line | Count | Source | 2260 | 3.34k | { | 2261 | | | 2262 | 3.34k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 3.34k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 3.34k | input_left.sanity_check(); | 2266 | 3.34k | input_to_mul.sanity_check(); | 2267 | 3.34k | input_quotient.sanity_check(); | 2268 | 5.85k | for (auto& el : to_add) { | 2269 | 5.85k | el.sanity_check(); | 2270 | 5.85k | } | 2271 | 3.35k | for (auto& el : input_remainders) { | 2272 | 3.35k | el.sanity_check(); | 2273 | 3.35k | } | 2274 | | | 2275 | 3.34k | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 3.34k | bigfield left = input_left; | 2278 | 3.34k | bigfield to_mul = input_to_mul; | 2279 | 3.34k | bigfield quotient = input_quotient; | 2280 | | | 2281 | 3.34k | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 3.34k | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 3.34k | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 3.34k | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 3.34k | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 3.34k | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 3.34k | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 3.34k | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 3.34k | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 3.34k | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 3.34k | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 3.34k | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 3.34k | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 3.34k | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 3.34k | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 3.34k | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 3.34k | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 3.34k | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 3.34k | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 3.34k | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 3.34k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 3.34k | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 3.34k | uint256_t borrow_lo_value = 0; | 2308 | 3.35k | for (const auto& remainder : input_remainders) { | 2309 | 3.35k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 3.35k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 3.35k | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 3.35k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 3.35k | } | 2315 | 3.34k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 3.34k | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 3.34k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 3.34k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 3.34k | uint512_t max_a0(0); | 2322 | 3.34k | uint512_t max_a1(0); | 2323 | 9.19k | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 5.85k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 5.85k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 5.85k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 5.85k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 5.85k | } | 2329 | 3.34k | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 3.34k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 3.34k | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 3.34k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 3.34k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 3.34k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 1.04k | ++max_lo_bits; | 2337 | 1.04k | } | 2338 | 3.34k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 1.66k | ++max_hi_bits; | 2340 | 1.66k | } | 2341 | | | 2342 | 3.34k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 3.34k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 3.34k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 3.34k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 3.34k | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 3.34k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 3.34k | bigfield output(input); | 2356 | 3.34k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 3.34k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 3.34k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 3.34k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 3.34k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 3.34k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 3.34k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 3.34k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 3.34k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 3.34k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 3.34k | output.context = ctx; | 2367 | 3.34k | return output; | 2368 | 3.34k | }; | 2369 | 3.34k | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 3.34k | if (to_mul.is_constant()) { | 2373 | 13 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 13 | } | 2375 | 3.34k | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 3.34k | if (remainders[0].is_constant()) { | 2379 | 10 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 10 | } | 2381 | | | 2382 | 3.34k | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 3.34k | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 3.34k | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 3.35k | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 15 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 15 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 15 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 15 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 15 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 15 | } | 2392 | 5.85k | for (const auto& add : to_add) { | 2393 | 5.85k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 5.85k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 5.85k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 5.85k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 5.85k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 5.85k | } | 2399 | | | 2400 | 3.34k | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 3.34k | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 3.34k | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 3.34k | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 3.34k | if (needs_normalize) { | 2406 | 320 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 320 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 320 | } | 2409 | | | 2410 | 3.34k | field_t<Builder> remainder_limbs[4]{ | 2411 | 3.34k | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 3.34k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 3.34k | : remainders[0].binary_basis_limbs[1].element, | 2414 | 3.34k | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 3.34k | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 3.34k | : remainders[0].binary_basis_limbs[3].element, | 2417 | 3.34k | }; | 2418 | 3.34k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 3.34k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 3.34k | { | 2422 | 3.34k | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 3.34k | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 3.34k | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 3.34k | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 3.34k | }, | 2427 | 3.34k | { | 2428 | 3.34k | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 3.34k | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 3.34k | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 3.34k | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 3.34k | }, | 2433 | 3.34k | { | 2434 | 3.34k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 3.34k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 3.34k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 3.34k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 3.34k | }, | 2439 | 3.34k | { | 2440 | 3.34k | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 3.34k | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 3.34k | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 3.34k | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 3.34k | }, | 2445 | 3.34k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 3.34k | modulus, | 2447 | 3.34k | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 3.34k | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 3.34k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 3.34k | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 3.34k | to_mul.prime_basis_limb, | 2454 | 3.34k | quotient.prime_basis_limb * neg_prime, | 2455 | 3.34k | -remainder_prime_limb); | 2456 | | | 2457 | 3.34k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 3.34k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 3.34k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 13 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 13 | lo.get_normalized_witness_index(), | 2465 | 13 | size_t(carry_hi_msb), | 2466 | 13 | size_t(carry_lo_msb)); | 2467 | 3.33k | } else { | 2468 | 3.33k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 3.33k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 3.33k | } | 2471 | 3.34k | } else { | 2472 | 3.34k | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 3.34k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 3.34k | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 3.34k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 3.34k | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 3.34k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 3.34k | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 3.34k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 3.34k | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 3.34k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 3.34k | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 3.34k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 3.34k | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 3.34k | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 3.34k | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 3.34k | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 3.34k | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 3.34k | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 3.34k | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 3.34k | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 3.34k | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 3.34k | const field_t r2 = c0.add_two(c1, c2); | 2503 | 3.34k | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 3.34k | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 3.34k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 3.34k | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 3.34k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 3.34k | for (const auto& add_element : to_add) { | 2510 | 3.34k | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 3.34k | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 3.34k | } | 2513 | 3.34k | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 3.34k | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 3.34k | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 3.34k | } | 2517 | 3.34k | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 3.34k | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 3.34k | carry_lo += borrow_lo; | 2520 | 3.34k | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 3.34k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 3.34k | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 3.34k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 3.34k | for (const auto& add_element : to_add) { | 2526 | 3.34k | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 3.34k | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 3.34k | } | 2529 | 3.34k | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 3.34k | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 3.34k | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 3.34k | } | 2533 | 3.34k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 3.34k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 3.34k | if (to_add.size() >= 2) { | 2537 | 3.34k | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 3.34k | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 3.34k | } | 2540 | 3.34k | } | 2541 | 3.34k | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 3.34k | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 3.34k | } | 2544 | 3.34k | if (remainders.size() >= 2) { | 2545 | 3.34k | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 3.34k | linear_terms = | 2547 | 3.34k | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 3.34k | } | 2549 | 3.34k | } | 2550 | 3.34k | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 3.34k | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 3.34k | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 3.34k | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 3.34k | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 3.34k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 3.34k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 3.34k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 3.34k | carry_combined = carry_combined.normalize(); | 2561 | 3.34k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 3.34k | carry_combined.get_normalized_witness_index(), | 2563 | 3.34k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 3.34k | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 3.34k | field_t<Builder> accumulator_midpoint = | 2566 | 3.34k | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 3.34k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 3.34k | } else { | 2569 | 3.34k | carry_lo = carry_lo.normalize(); | 2570 | 3.34k | carry_hi = carry_hi.normalize(); | 2571 | 3.34k | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 3.34k | static_cast<size_t>(carry_lo_msb), | 2573 | 3.34k | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 3.34k | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 3.34k | static_cast<size_t>(carry_hi_msb), | 2576 | 3.34k | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 3.34k | } | 2578 | 3.34k | } | 2579 | 3.34k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ Line | Count | Source | 2260 | 40 | { | 2261 | | | 2262 | 40 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2263 | 40 | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2264 | | // Sanity checks | 2265 | 40 | input_left.sanity_check(); | 2266 | 40 | input_to_mul.sanity_check(); | 2267 | 40 | input_quotient.sanity_check(); | 2268 | 40 | for (auto& el : to_add) { | 2269 | 10 | el.sanity_check(); | 2270 | 10 | } | 2271 | 40 | for (auto& el : input_remainders) { | 2272 | 40 | el.sanity_check(); | 2273 | 40 | } | 2274 | | | 2275 | 40 | std::vector<bigfield> remainders(input_remainders); | 2276 | | | 2277 | 40 | bigfield left = input_left; | 2278 | 40 | bigfield to_mul = input_to_mul; | 2279 | 40 | bigfield quotient = input_quotient; | 2280 | | | 2281 | 40 | Builder* ctx = left.context ? left.context : to_mul.context; | 2282 | | | 2283 | 40 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2284 | 40 | max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2285 | 40 | uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2286 | 40 | max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2287 | 40 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2288 | 40 | max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2289 | 40 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2290 | 40 | max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2291 | 40 | uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2292 | 40 | max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2293 | 40 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value); | 2294 | 40 | max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2295 | 40 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value); | 2296 | 40 | max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2297 | 40 | uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value); | 2298 | 40 | max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2299 | 40 | uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value); | 2300 | 40 | max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2301 | | | 2302 | 40 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value; | 2303 | 40 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2304 | | | 2305 | 40 | uint512_t max_r1 = max_b0 + max_b1; | 2306 | | | 2307 | 40 | uint256_t borrow_lo_value = 0; | 2308 | 40 | for (const auto& remainder : input_remainders) { | 2309 | 40 | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2310 | 40 | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2311 | | | 2312 | 40 | borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value + | 2313 | 40 | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS)); | 2314 | 40 | } | 2315 | 40 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2316 | 40 | field_t borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2317 | | | 2318 | 40 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2319 | 40 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2320 | | | 2321 | 40 | uint512_t max_a0(0); | 2322 | 40 | uint512_t max_a1(0); | 2323 | 50 | for (size_t i = 0; i < to_add.size(); ++i) { | 2324 | 10 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2325 | 10 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2326 | 10 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2327 | 10 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2328 | 10 | } | 2329 | 40 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 2330 | 40 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2331 | 40 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry; | 2332 | | | 2333 | 40 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2334 | 40 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2335 | 40 | if ((max_lo_bits & 1ULL) == 1ULL) { | 2336 | 0 | ++max_lo_bits; | 2337 | 0 | } | 2338 | 40 | if ((max_hi_bits & 1ULL) == 1ULL) { | 2339 | 10 | ++max_hi_bits; | 2340 | 10 | } | 2341 | | | 2342 | 40 | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2343 | 40 | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2344 | | | 2345 | 40 | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2346 | 0 | carry_lo_msb = 0; | 2347 | 0 | } | 2348 | 40 | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2349 | 0 | carry_hi_msb = 0; | 2350 | 0 | } | 2351 | 40 | if constexpr (HasPlookup<Builder>) { | 2352 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2353 | | // If we're using constant values, instantiate them as circuit variables | 2354 | 40 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2355 | 40 | bigfield output(input); | 2356 | 40 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2357 | 40 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2358 | 40 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2359 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2360 | 40 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2361 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2362 | 40 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2363 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2364 | 40 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2365 | 40 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2366 | 40 | output.context = ctx; | 2367 | 40 | return output; | 2368 | 40 | }; | 2369 | 40 | if (left.is_constant()) { | 2370 | 0 | left = convert_constant_to_fixed_witness(left); | 2371 | 0 | } | 2372 | 40 | if (to_mul.is_constant()) { | 2373 | 30 | to_mul = convert_constant_to_fixed_witness(to_mul); | 2374 | 30 | } | 2375 | 40 | if (quotient.is_constant()) { | 2376 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2377 | 0 | } | 2378 | 40 | if (remainders[0].is_constant()) { | 2379 | 10 | remainders[0] = convert_constant_to_fixed_witness(remainders[0]); | 2380 | 10 | } | 2381 | | | 2382 | 40 | std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element }; | 2383 | 40 | std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element }; | 2384 | 40 | std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb }; | 2385 | 40 | for (size_t i = 1; i < remainders.size(); ++i) { | 2386 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2387 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2388 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2389 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2390 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2391 | 0 | } | 2392 | 40 | for (const auto& add : to_add) { | 2393 | 10 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2394 | 10 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2395 | 10 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2396 | 10 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2397 | 10 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2398 | 10 | } | 2399 | | | 2400 | 40 | const auto& t0 = remainders[0].binary_basis_limbs[1].element; | 2401 | 40 | const auto& t1 = remainders[0].binary_basis_limbs[3].element; | 2402 | 40 | bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1); | 2403 | 40 | needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1); | 2404 | | | 2405 | 40 | if (needs_normalize) { | 2406 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1); | 2407 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1); | 2408 | 0 | } | 2409 | | | 2410 | 40 | field_t<Builder> remainder_limbs[4]{ | 2411 | 40 | field_t<Builder>::accumulate(limb_0_accumulator), | 2412 | 40 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2413 | 40 | : remainders[0].binary_basis_limbs[1].element, | 2414 | 40 | field_t<Builder>::accumulate(limb_2_accumulator), | 2415 | 40 | needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2416 | 40 | : remainders[0].binary_basis_limbs[3].element, | 2417 | 40 | }; | 2418 | 40 | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2419 | | | 2420 | 40 | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2421 | 40 | { | 2422 | 40 | left.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2423 | 40 | left.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2424 | 40 | left.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2425 | 40 | left.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2426 | 40 | }, | 2427 | 40 | { | 2428 | 40 | to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2429 | 40 | to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2430 | 40 | to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2431 | 40 | to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2432 | 40 | }, | 2433 | 40 | { | 2434 | 40 | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2435 | 40 | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2436 | 40 | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2437 | 40 | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2438 | 40 | }, | 2439 | 40 | { | 2440 | 40 | remainder_limbs[0].get_normalized_witness_index(), | 2441 | 40 | remainder_limbs[1].get_normalized_witness_index(), | 2442 | 40 | remainder_limbs[2].get_normalized_witness_index(), | 2443 | 40 | remainder_limbs[3].get_normalized_witness_index(), | 2444 | 40 | }, | 2445 | 40 | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2446 | 40 | modulus, | 2447 | 40 | }; | 2448 | | // N.B. this method also evaluates the prime field component of the non-native field mul | 2449 | 40 | const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2450 | | | 2451 | 40 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2452 | 40 | field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb, | 2453 | 40 | to_mul.prime_basis_limb, | 2454 | 40 | quotient.prime_basis_limb * neg_prime, | 2455 | 40 | -remainder_prime_limb); | 2456 | | | 2457 | 40 | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo; | 2458 | 40 | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx); | 2459 | | | 2460 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2461 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2462 | 40 | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2463 | 30 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2464 | 30 | lo.get_normalized_witness_index(), | 2465 | 30 | size_t(carry_hi_msb), | 2466 | 30 | size_t(carry_lo_msb)); | 2467 | 30 | } else { | 2468 | 10 | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2469 | 10 | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2470 | 10 | } | 2471 | 40 | } else { | 2472 | 40 | const field_t b0 = left.binary_basis_limbs[1].element.madd( | 2473 | 40 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2474 | 40 | const field_t b1 = left.binary_basis_limbs[0].element.madd( | 2475 | 40 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2476 | 40 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 2477 | 40 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2478 | 40 | const field_t c1 = left.binary_basis_limbs[2].element.madd( | 2479 | 40 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2480 | 40 | const field_t c2 = left.binary_basis_limbs[0].element.madd( | 2481 | 40 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2482 | 40 | const field_t d0 = left.binary_basis_limbs[3].element.madd( | 2483 | 40 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2484 | 40 | const field_t d1 = left.binary_basis_limbs[2].element.madd( | 2485 | 40 | to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2486 | 40 | const field_t d2 = left.binary_basis_limbs[1].element.madd( | 2487 | 40 | to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2488 | 40 | const field_t d3 = left.binary_basis_limbs[0].element.madd( | 2489 | 40 | to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2490 | | | 2491 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 2492 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 2493 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 2494 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 2495 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 2496 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 2497 | | | 2498 | 40 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 2499 | 40 | to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 2500 | | | 2501 | 40 | field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element); | 2502 | 40 | const field_t r2 = c0.add_two(c1, c2); | 2503 | 40 | const field_t r3 = d0 + d1.add_two(d2, d3); | 2504 | | | 2505 | 40 | field_t carry_lo_0 = r0 * shift_right_2; | 2506 | 40 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 2507 | 40 | field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2); | 2508 | 40 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 2509 | 40 | for (const auto& add_element : to_add) { | 2510 | 40 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 2511 | 40 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2512 | 40 | } | 2513 | 40 | for (size_t i = 1; i < remainders.size(); ++i) { | 2514 | 40 | carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2, | 2515 | 40 | -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 2516 | 40 | } | 2517 | 40 | field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element, | 2518 | 40 | -(remainders[0].binary_basis_limbs[3].element * shift_1)); | 2519 | 40 | carry_lo += borrow_lo; | 2520 | 40 | field_t carry_hi_0 = r2 * shift_right_2; | 2521 | 40 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 2522 | 40 | field_t carry_hi_2 = t1 * shift_right_2; | 2523 | 40 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 2524 | | | 2525 | 40 | for (const auto& add_element : to_add) { | 2526 | 40 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 2527 | 40 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2528 | 40 | } | 2529 | 40 | for (size_t i = 1; i < remainders.size(); ++i) { | 2530 | 40 | carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2, | 2531 | 40 | -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 2532 | 40 | } | 2533 | 40 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2534 | | | 2535 | 40 | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 2536 | 40 | if (to_add.size() >= 2) { | 2537 | 40 | for (size_t i = 0; i < to_add.size(); i += 2) { | 2538 | 40 | linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb); | 2539 | 40 | } | 2540 | 40 | } | 2541 | 40 | if ((to_add.size() & 1UL) == 1UL) { | 2542 | 40 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 2543 | 40 | } | 2544 | 40 | if (remainders.size() >= 2) { | 2545 | 40 | for (size_t i = 0; i < (remainders.size() >> 1); i += 1) { | 2546 | 40 | linear_terms = | 2547 | 40 | linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb); | 2548 | 40 | } | 2549 | 40 | } | 2550 | 40 | if ((remainders.size() & 1UL) == 1UL) { | 2551 | 40 | linear_terms += -remainders[remainders.size() - 1].prime_basis_limb; | 2552 | 40 | } | 2553 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 2554 | 40 | field_t<Builder>::evaluate_polynomial_identity( | 2555 | 40 | left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 2556 | | | 2557 | 40 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 2558 | 40 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 2559 | 40 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 2560 | 40 | carry_combined = carry_combined.normalize(); | 2561 | 40 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 2562 | 40 | carry_combined.get_normalized_witness_index(), | 2563 | 40 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 2564 | 40 | "bigfield: carry_combined too large in unsafe_evaluate_multiply_add."); | 2565 | 40 | field_t<Builder> accumulator_midpoint = | 2566 | 40 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 2567 | 40 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 2568 | 40 | } else { | 2569 | 40 | carry_lo = carry_lo.normalize(); | 2570 | 40 | carry_hi = carry_hi.normalize(); | 2571 | 40 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 2572 | 40 | static_cast<size_t>(carry_lo_msb), | 2573 | 40 | "bigfield: carry_lo too large in unsafe_evaluate_multiply_add."); | 2574 | 40 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 2575 | 40 | static_cast<size_t>(carry_hi_msb), | 2576 | 40 | "bigfield: carry_hi too large in unsafe_evaluate_multiply_add."); | 2577 | 40 | } | 2578 | 40 | } | 2579 | 40 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ |
2580 | | /** |
2581 | | * Evaluate a quadratic relation involving multiple multiplications |
2582 | | * |
2583 | | * i.e. evalaute: |
2584 | | * |
2585 | | * (left_0 * right_0) + ... + (left_n-1 * right_n-1) + ...to_add - (input_quotient * q + ...input_remainders) = 0 |
2586 | | * |
2587 | | * This method supports multiple "remainders" because, when evaluating divisions, some of these remainders are terms |
2588 | | * We're subtracting from our product (see msub_div for more details) |
2589 | | * |
2590 | | * The above quadratic relation can be evaluated using only a single quotient/remainder term. |
2591 | | * |
2592 | | * Params: |
2593 | | * |
2594 | | * `input_left`: left multiplication operands |
2595 | | * `input_right` : right multiplication operands |
2596 | | * `to_add` : vector of elements to add to the product |
2597 | | * `input_quotient` : quotient |
2598 | | * `input_remainders` : vector of remainders |
2599 | | * |
2600 | | * THIS METHOD IS UNSAFE TO USE IN CIRCUITS DIRECTLY AS IT LACKS OVERFLOW CHECKS. |
2601 | | **/ |
2602 | | template <typename Builder, typename T> |
2603 | | void bigfield<Builder, T>::unsafe_evaluate_multiple_multiply_add(const std::vector<bigfield>& input_left, |
2604 | | const std::vector<bigfield>& input_right, |
2605 | | const std::vector<bigfield>& to_add, |
2606 | | const bigfield& input_quotient, |
2607 | | const std::vector<bigfield>& input_remainders) |
2608 | 370k | { |
2609 | 370k | ASSERT(input_left.size() == input_right.size()); |
2610 | 370k | ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT); |
2611 | 370k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
2612 | 370k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); |
2613 | | |
2614 | 370k | ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024); |
2615 | | // Sanity checks |
2616 | 824k | for (auto& el : input_left) { |
2617 | 824k | el.sanity_check(); |
2618 | 824k | } |
2619 | 824k | for (auto& el : input_right) { |
2620 | 824k | el.sanity_check(); |
2621 | 824k | } |
2622 | 653k | for (auto& el : to_add) { |
2623 | 653k | el.sanity_check(); |
2624 | 653k | } |
2625 | 0 | input_quotient.sanity_check(); |
2626 | 370k | for (auto& el : input_remainders) { |
2627 | 370k | el.sanity_check(); |
2628 | 370k | } |
2629 | 0 | std::vector<bigfield> remainders(input_remainders); |
2630 | 0 | std::vector<bigfield> left(input_left); |
2631 | 0 | std::vector<bigfield> right(input_right); |
2632 | 0 | bigfield quotient = input_quotient; |
2633 | 0 | const size_t num_multiplications = input_left.size(); |
2634 | |
|
2635 | 370k | Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context; |
2636 | |
|
2637 | 824k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { |
2638 | 824k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); |
2639 | 824k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); |
2640 | 824k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); |
2641 | 824k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); |
2642 | 824k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); |
2643 | 824k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); |
2644 | 824k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); |
2645 | 824k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); |
2646 | 824k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); |
2647 | 824k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; |
2648 | | |
2649 | 824k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; |
2650 | 824k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; |
2651 | 824k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; |
2652 | 824k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); |
2653 | 824k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); |
2654 | 824k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); |
2655 | 824k | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_ Line | Count | Source | 2637 | 743k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 743k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 743k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 743k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 743k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 743k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 743k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 743k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 743k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 743k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 743k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 743k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 743k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 743k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 743k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 743k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 743k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 743k | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_SF_E_clESF_SF_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_ Line | Count | Source | 2637 | 3.15k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 3.15k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 3.15k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 3.15k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 3.15k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 3.15k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 3.15k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 3.15k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 3.15k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 3.15k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 3.15k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 3.15k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 3.15k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 3.15k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 3.15k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 3.15k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 3.15k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 3.15k | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_ _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_ Line | Count | Source | 2637 | 70.5k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 70.5k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 70.5k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 70.5k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 70.5k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 70.5k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 70.5k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 70.5k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 70.5k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 70.5k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 70.5k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 70.5k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 70.5k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 70.5k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 70.5k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 70.5k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 70.5k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 70.5k | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_ Line | Count | Source | 2637 | 7.01k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 7.01k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 7.01k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 7.01k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 7.01k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 7.01k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 7.01k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 7.01k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 7.01k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 7.01k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 7.01k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 7.01k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 7.01k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 7.01k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 7.01k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 7.01k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 7.01k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 7.01k | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_ |
2656 | | |
2657 | | /** |
2658 | | * Step 1: Compute the maximum potential value of our product limbs |
2659 | | * |
2660 | | * max_lo = maximum value of limb products that span the range 0 - 2^{3t} |
2661 | | * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t} |
2662 | | * (t = NUM_LIMB_BITS) |
2663 | | **/ |
2664 | 0 | uint512_t max_lo = 0; |
2665 | 0 | uint512_t max_hi = 0; |
2666 | | |
2667 | | // Compute max values of quotient product limb products |
2668 | 0 | uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); |
2669 | 0 | uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); |
2670 | 0 | uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); |
2671 | 0 | uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); |
2672 | 0 | uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); |
2673 | 0 | uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); |
2674 | 0 | uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); |
2675 | 0 | uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); |
2676 | 0 | uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); |
2677 | | |
2678 | | // max_r0 = terms from 0 - 2^2t |
2679 | | // max_r1 = terms from 2^t - 2^3t |
2680 | | // max_r2 = terms from 2^2t - 2^4t |
2681 | | // max_r3 = terms from 2^3t - 2^5t |
2682 | 0 | uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); |
2683 | 0 | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); |
2684 | 0 | uint512_t max_r1 = max_b0 + max_b1; |
2685 | |
|
2686 | 0 | uint256_t borrow_lo_value(0); |
2687 | 370k | for (const auto& remainder : input_remainders) { |
2688 | 370k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; |
2689 | 370k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; |
2690 | | |
2691 | 370k | borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value + |
2692 | 370k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); |
2693 | 370k | } |
2694 | 0 | borrow_lo_value >>= 2 * NUM_LIMB_BITS; |
2695 | 0 | field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value)); |
2696 | |
|
2697 | 0 | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; |
2698 | 0 | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; |
2699 | | |
2700 | | // update max_lo, max_hi with quotient limb product terms. |
2701 | 0 | max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS); |
2702 | 0 | max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS); |
2703 | | |
2704 | | // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi |
2705 | 0 | uint512_t max_a0(0); |
2706 | 0 | uint512_t max_a1(0); |
2707 | 1.02M | for (size_t i = 0; i < to_add.size(); ++i) { |
2708 | 653k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + |
2709 | 653k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); |
2710 | 653k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + |
2711 | 653k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); |
2712 | 653k | } |
2713 | 0 | max_lo += max_a0; |
2714 | 0 | max_hi += max_a1; |
2715 | | |
2716 | | // Compute the maximum value of our multiplication products and add to max_lo, max_hi |
2717 | 1.19M | for (size_t i = 0; i < num_multiplications; ++i) { |
2718 | 824k | const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]); |
2719 | 824k | max_lo += product_lo; |
2720 | 824k | max_hi += product_hi; |
2721 | 824k | } |
2722 | |
|
2723 | 0 | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); |
2724 | 0 | max_hi += max_lo_carry; |
2725 | | // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we |
2726 | | // will need to apply to validate our product |
2727 | 0 | uint64_t max_lo_bits = (max_lo.get_msb() + 1); |
2728 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; |
2729 | | // Turbo range checks only work for even bit ranges, so make sure these values are even |
2730 | | // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges... |
2731 | 370k | if ((max_lo_bits & 1ULL) == 1ULL) { |
2732 | 78.9k | ++max_lo_bits; |
2733 | 78.9k | } |
2734 | 370k | if ((max_hi_bits & 1ULL) == 1ULL) { |
2735 | 323k | ++max_hi_bits; |
2736 | 323k | } |
2737 | |
|
2738 | 370k | if constexpr (HasPlookup<Builder>) { |
2739 | | // The plookup custom bigfield gate requires inputs are witnesses. |
2740 | | // If we're using constant values, instantiate them as circuit variables |
2741 | | |
2742 | 370k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { |
2743 | 5 | bigfield output(input); |
2744 | 5 | output.prime_basis_limb = field_t<Builder>::from_witness_index( |
2745 | 5 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); |
2746 | 5 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( |
2747 | 5 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); |
2748 | 5 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( |
2749 | 5 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); |
2750 | 5 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( |
2751 | 5 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); |
2752 | 5 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( |
2753 | 5 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); |
2754 | 5 | output.context = ctx; |
2755 | 5 | return output; |
2756 | 5 | }; _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_ Line | Count | Source | 2742 | 1 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 1 | bigfield output(input); | 2744 | 1 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 1 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 1 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 1 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 1 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 1 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 1 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 1 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 1 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 1 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 1 | output.context = ctx; | 2755 | 1 | return output; | 2756 | 1 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_E_clESF_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_ _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_ Line | Count | Source | 2742 | 4 | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 4 | bigfield output(input); | 2744 | 4 | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 4 | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 4 | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 4 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 4 | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 4 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 4 | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 4 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 4 | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 4 | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 4 | output.context = ctx; | 2755 | 4 | return output; | 2756 | 4 | }; |
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_ Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_ |
2757 | | |
2758 | | // evalaute a nnf mul and add into existing lohi output for our extra product terms |
2759 | | // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx |
2760 | | // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136} |
2761 | | // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values |
2762 | | // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication + |
2763 | | // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If |
2764 | | // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into |
2765 | | // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting |
2766 | | // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two |
2767 | | // calls to `evaluate_non_native_field_multiplication` |
2768 | 370k | std::vector<field_t<Builder>> limb_0_accumulator; |
2769 | 370k | std::vector<field_t<Builder>> limb_2_accumulator; |
2770 | 370k | std::vector<field_t<Builder>> prime_limb_accumulator; |
2771 | | |
2772 | 1.19M | for (size_t i = 0; i < num_multiplications; ++i) { |
2773 | 824k | if (i == 0 && left[0].is_constant()) { |
2774 | 0 | left[0] = convert_constant_to_fixed_witness(left[0]); |
2775 | 0 | } |
2776 | 824k | if (i == 0 && right[0].is_constant()) { |
2777 | 1 | right[0] = convert_constant_to_fixed_witness(right[0]); |
2778 | 1 | } |
2779 | 824k | if (i > 0 && left[i].is_constant()) { |
2780 | 0 | left[i] = convert_constant_to_fixed_witness(left[i]); |
2781 | 0 | } |
2782 | 824k | if (i > 0 && right[i].is_constant()) { |
2783 | 4 | right[i] = convert_constant_to_fixed_witness(right[i]); |
2784 | 4 | } |
2785 | | |
2786 | 824k | if (i > 0) { |
2787 | 454k | bb::non_native_field_witnesses<bb::fr> mul_witnesses = { |
2788 | 454k | { |
2789 | 454k | left[i].binary_basis_limbs[0].element.get_normalized_witness_index(), |
2790 | 454k | left[i].binary_basis_limbs[1].element.get_normalized_witness_index(), |
2791 | 454k | left[i].binary_basis_limbs[2].element.get_normalized_witness_index(), |
2792 | 454k | left[i].binary_basis_limbs[3].element.get_normalized_witness_index(), |
2793 | 454k | }, |
2794 | 454k | { |
2795 | 454k | right[i].binary_basis_limbs[0].element.get_normalized_witness_index(), |
2796 | 454k | right[i].binary_basis_limbs[1].element.get_normalized_witness_index(), |
2797 | 454k | right[i].binary_basis_limbs[2].element.get_normalized_witness_index(), |
2798 | 454k | right[i].binary_basis_limbs[3].element.get_normalized_witness_index(), |
2799 | 454k | }, |
2800 | 454k | { |
2801 | 454k | ctx->zero_idx, |
2802 | 454k | ctx->zero_idx, |
2803 | 454k | ctx->zero_idx, |
2804 | 454k | ctx->zero_idx, |
2805 | 454k | }, |
2806 | 454k | { |
2807 | 454k | ctx->zero_idx, |
2808 | 454k | ctx->zero_idx, |
2809 | 454k | ctx->zero_idx, |
2810 | 454k | ctx->zero_idx, |
2811 | 454k | }, |
2812 | 454k | { 0, 0, 0, 0 }, |
2813 | 454k | modulus, |
2814 | 454k | }; |
2815 | | |
2816 | 454k | const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses); |
2817 | | |
2818 | 454k | field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx); |
2819 | 454k | field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx); |
2820 | | |
2821 | 454k | limb_0_accumulator.emplace_back(-lo_2); |
2822 | 454k | limb_2_accumulator.emplace_back(-hi_2); |
2823 | 454k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); |
2824 | 454k | } |
2825 | 824k | } |
2826 | 370k | if (quotient.is_constant()) { |
2827 | 0 | quotient = convert_constant_to_fixed_witness(quotient); |
2828 | 0 | } |
2829 | | |
2830 | 370k | bool no_remainders = remainders.size() == 0; |
2831 | 370k | if (!no_remainders) { |
2832 | 370k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); |
2833 | 370k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); |
2834 | 370k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); |
2835 | 370k | } |
2836 | 370k | for (size_t i = 1; i < remainders.size(); ++i) { |
2837 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); |
2838 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); |
2839 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); |
2840 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); |
2841 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); |
2842 | 0 | } |
2843 | 653k | for (const auto& add : to_add) { |
2844 | 653k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); |
2845 | 653k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); |
2846 | 653k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); |
2847 | 653k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); |
2848 | 653k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); |
2849 | 653k | } |
2850 | | |
2851 | 370k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); |
2852 | 370k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); |
2853 | 370k | if (accumulated_lo.is_constant()) { |
2854 | 0 | accumulated_lo = |
2855 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); |
2856 | 0 | } |
2857 | 370k | if (accumulated_hi.is_constant()) { |
2858 | 0 | accumulated_hi = |
2859 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); |
2860 | 0 | } |
2861 | 370k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
2862 | 370k | : remainders[0].binary_basis_limbs[1].element; |
2863 | 370k | if (remainder1.is_constant()) { |
2864 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); |
2865 | 0 | } |
2866 | 370k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
2867 | 370k | : remainders[0].binary_basis_limbs[3].element; |
2868 | 370k | if (remainder3.is_constant()) { |
2869 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); |
2870 | 0 | } |
2871 | 370k | field_t<Builder> remainder_limbs[4]{ |
2872 | 370k | accumulated_lo, |
2873 | 370k | remainder1, |
2874 | 370k | accumulated_hi, |
2875 | 370k | remainder3, |
2876 | 370k | }; |
2877 | 370k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); |
2878 | | |
2879 | 370k | bb::non_native_field_witnesses<bb::fr> witnesses{ |
2880 | 370k | { |
2881 | 370k | left[0].binary_basis_limbs[0].element.get_normalized_witness_index(), |
2882 | 370k | left[0].binary_basis_limbs[1].element.get_normalized_witness_index(), |
2883 | 370k | left[0].binary_basis_limbs[2].element.get_normalized_witness_index(), |
2884 | 370k | left[0].binary_basis_limbs[3].element.get_normalized_witness_index(), |
2885 | 370k | }, |
2886 | 370k | { |
2887 | 370k | right[0].binary_basis_limbs[0].element.get_normalized_witness_index(), |
2888 | 370k | right[0].binary_basis_limbs[1].element.get_normalized_witness_index(), |
2889 | 370k | right[0].binary_basis_limbs[2].element.get_normalized_witness_index(), |
2890 | 370k | right[0].binary_basis_limbs[3].element.get_normalized_witness_index(), |
2891 | 370k | }, |
2892 | 370k | { |
2893 | 370k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), |
2894 | 370k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), |
2895 | 370k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), |
2896 | 370k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), |
2897 | 370k | }, |
2898 | 370k | { |
2899 | 370k | remainder_limbs[0].get_normalized_witness_index(), |
2900 | 370k | remainder_limbs[1].get_normalized_witness_index(), |
2901 | 370k | remainder_limbs[2].get_normalized_witness_index(), |
2902 | 370k | remainder_limbs[3].get_normalized_witness_index(), |
2903 | 370k | }, |
2904 | 370k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, |
2905 | 370k | modulus, |
2906 | 370k | }; |
2907 | | |
2908 | 370k | const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); |
2909 | | |
2910 | 370k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); |
2911 | | |
2912 | 370k | field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb, |
2913 | 370k | right[0].prime_basis_limb, |
2914 | 370k | quotient.prime_basis_limb * neg_prime, |
2915 | 370k | -remainder_prime_limb); |
2916 | | |
2917 | 370k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo; |
2918 | 370k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx); |
2919 | | |
2920 | 370k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); |
2921 | 370k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); |
2922 | | |
2923 | 370k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { |
2924 | 0 | carry_lo_msb = 0; |
2925 | 0 | } |
2926 | 370k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { |
2927 | 0 | carry_hi_msb = 0; |
2928 | 0 | } |
2929 | | |
2930 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom |
2931 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) |
2932 | 370k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { |
2933 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), |
2934 | 0 | lo.get_normalized_witness_index(), |
2935 | 0 | (size_t)carry_hi_msb, |
2936 | 0 | (size_t)carry_lo_msb); |
2937 | 370k | } else { |
2938 | 370k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); |
2939 | 370k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); |
2940 | 370k | } |
2941 | | /* NOTE TO AUDITOR: An extraneous block |
2942 | | if constexpr (HasPlookup<Builder>) { |
2943 | | carry_lo = carry_lo.normalize(); |
2944 | | carry_hi = carry_hi.normalize(); |
2945 | | ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb)); |
2946 | | ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb)); |
2947 | | } |
2948 | | was removed from the `else` block below. See the conversation at |
2949 | | https://github.com/AztecProtocol/aztec2-internal/pull/1023 |
2950 | | We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint |
2951 | | was just imposed?). */ |
2952 | 370k | } else { |
2953 | 0 | field_t b0 = left[0].binary_basis_limbs[1].element.madd( |
2954 | 0 | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); |
2955 | 0 | field_t b1 = left[0].binary_basis_limbs[0].element.madd( |
2956 | 0 | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); |
2957 | 0 | field_t c0 = left[0].binary_basis_limbs[1].element.madd( |
2958 | 0 | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); |
2959 | 0 | field_t c1 = left[0].binary_basis_limbs[2].element.madd( |
2960 | 0 | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); |
2961 | 0 | field_t c2 = left[0].binary_basis_limbs[0].element.madd( |
2962 | 0 | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); |
2963 | 0 | field_t d0 = left[0].binary_basis_limbs[3].element.madd( |
2964 | 0 | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); |
2965 | 0 | field_t d1 = left[0].binary_basis_limbs[2].element.madd( |
2966 | 0 | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); |
2967 | 0 | field_t d2 = left[0].binary_basis_limbs[1].element.madd( |
2968 | 0 | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); |
2969 | 0 | field_t d3 = left[0].binary_basis_limbs[0].element.madd( |
2970 | 0 | right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); |
2971 | | |
2972 | | /** |
2973 | | * Compute "limb accumulators" |
2974 | | * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t} |
2975 | | * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS) |
2976 | | * Actual range will vary a few bits because of lazy reduction techniques |
2977 | | * |
2978 | | * We store these values in an "accumulator" vector in order to efficiently add them into a sum. |
2979 | | * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator) |
2980 | | * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single |
2981 | | * custom gate. |
2982 | | **/ |
2983 | |
|
2984 | 0 | std::vector<field_t<Builder>> limb_0_accumulator; |
2985 | 0 | std::vector<field_t<Builder>> limb_2_accumulator; |
2986 | 0 | std::vector<field_t<Builder>> prime_limb_accumulator; |
2987 | | |
2988 | | // Add remaining products into the limb accumulators. |
2989 | | // We negate the product values because the accumulator values itself will be negated |
2990 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact |
2991 | | // that the accumulators originaly tracked the remainder term (which is negated) |
2992 | |
|
2993 | 0 | for (size_t i = 1; i < num_multiplications; ++i) { |
2994 | 0 | field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element; |
2995 | 0 | lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2); |
2996 | 0 | lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2); |
2997 | 0 | field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element; |
2998 | 0 | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2); |
2999 | 0 | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2); |
3000 | 0 | hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2); |
3001 | 0 | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2); |
3002 | 0 | hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2); |
3003 | 0 | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2); |
3004 | |
|
3005 | 0 | limb_0_accumulator.emplace_back(-lo_2); |
3006 | 0 | limb_2_accumulator.emplace_back(-hi_2); |
3007 | 0 | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); |
3008 | 0 | } |
3009 | | // add cached products into the limb accumulators. |
3010 | | // We negate the cache values because the accumulator values itself will be negated |
3011 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact |
3012 | | // that the accumulators originaly tracked the remainder term (which is negated) |
3013 | | |
3014 | | // Update the accumulators with the remainder terms. First check we actually have remainder terms! |
3015 | | //(not present when we're checking a product is 0 mod p). See `assert_is_in_field` |
3016 | |
|
3017 | 0 | bool no_remainders = remainders.size() == 0; |
3018 | 0 | if (!no_remainders) { |
3019 | 0 | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); |
3020 | 0 | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); |
3021 | 0 | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); |
3022 | 0 | } |
3023 | 0 | for (size_t i = 1; i < remainders.size(); ++i) { |
3024 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); |
3025 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); |
3026 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); |
3027 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); |
3028 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); |
3029 | 0 | } |
3030 | 0 | for (const auto& add : to_add) { |
3031 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); |
3032 | 0 | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); |
3033 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); |
3034 | 0 | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); |
3035 | 0 | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); |
3036 | 0 | } |
3037 | |
|
3038 | 0 | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); |
3039 | 0 | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); |
3040 | 0 | if (accumulated_lo.is_constant()) { |
3041 | 0 | accumulated_lo = |
3042 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); |
3043 | 0 | } |
3044 | 0 | if (accumulated_hi.is_constant()) { |
3045 | 0 | accumulated_hi = |
3046 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); |
3047 | 0 | } |
3048 | 0 | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
3049 | 0 | : remainders[0].binary_basis_limbs[1].element; |
3050 | 0 | if (remainder1.is_constant()) { |
3051 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); |
3052 | 0 | } |
3053 | 0 | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) |
3054 | 0 | : remainders[0].binary_basis_limbs[3].element; |
3055 | 0 | if (remainder3.is_constant()) { |
3056 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); |
3057 | 0 | } |
3058 | 0 | field_t<Builder> remainder_limbs[4]{ |
3059 | 0 | accumulated_lo, |
3060 | 0 | remainder1, |
3061 | 0 | accumulated_hi, |
3062 | 0 | remainder3, |
3063 | 0 | }; |
3064 | 0 | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); |
3065 | | |
3066 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb |
3067 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap |
3068 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion |
3069 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning |
3070 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are |
3071 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} |
3072 | |
|
3073 | 0 | field_t r0 = left[0].binary_basis_limbs[0].element.madd( |
3074 | 0 | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); |
3075 | 0 | field_t r1 = b0.add_two(b1, -remainder_limbs[1]); |
3076 | 0 | const field_t r2 = c0.add_two(c1, c2); |
3077 | 0 | const field_t r3 = d0 + d1.add_two(d2, d3); |
3078 | |
|
3079 | 0 | field_t carry_lo_0 = r0 * shift_right_2; |
3080 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); |
3081 | 0 | field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2); |
3082 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); |
3083 | |
|
3084 | 0 | field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1)); |
3085 | 0 | carry_lo += borrow_lo; |
3086 | 0 | field_t carry_hi_0 = r2 * shift_right_2; |
3087 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); |
3088 | 0 | field_t carry_hi_2 = t1 * shift_right_2; |
3089 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); |
3090 | |
|
3091 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); |
3092 | |
|
3093 | 0 | field_t<Builder> linear_terms(ctx, bb::fr(0)); |
3094 | |
|
3095 | 0 | linear_terms += -remainder_prime_limb; |
3096 | | |
3097 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) |
3098 | 0 | field_t<Builder>::evaluate_polynomial_identity( |
3099 | 0 | left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); |
3100 | |
|
3101 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); |
3102 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); |
3103 | |
|
3104 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); |
3105 | |
|
3106 | 0 | if constexpr (HasPlookup<Builder>) { |
3107 | 0 | carry_lo = carry_lo.normalize(); |
3108 | 0 | carry_hi = carry_hi.normalize(); |
3109 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), |
3110 | 0 | static_cast<size_t>(carry_lo_msb)); |
3111 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), |
3112 | 0 | static_cast<size_t>(carry_hi_msb)); |
3113 | |
|
3114 | 0 | } else { |
3115 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { |
3116 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); |
3117 | 0 | carry_combined = carry_combined.normalize(); |
3118 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( |
3119 | 0 | carry_combined.get_normalized_witness_index(), |
3120 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), |
3121 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add."); |
3122 | 0 | field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index( |
3123 | 0 | ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); |
3124 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); |
3125 | 0 | } else { |
3126 | 0 | carry_lo = carry_lo.normalize(); |
3127 | 0 | carry_hi = carry_hi.normalize(); |
3128 | 0 | ctx->decompose_into_base4_accumulators( |
3129 | 0 | carry_lo.get_normalized_witness_index(), |
3130 | 0 | static_cast<size_t>(carry_lo_msb), |
3131 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add."); |
3132 | 0 | ctx->decompose_into_base4_accumulators( |
3133 | 0 | carry_hi.get_normalized_witness_index(), |
3134 | 0 | static_cast<size_t>(carry_hi_msb), |
3135 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add."); |
3136 | 0 | } |
3137 | 0 | } |
3138 | 0 | } |
3139 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ Line | Count | Source | 2608 | 338k | { | 2609 | 338k | ASSERT(input_left.size() == input_right.size()); | 2610 | 338k | ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT); | 2611 | 338k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2612 | 338k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2613 | | | 2614 | 338k | ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024); | 2615 | | // Sanity checks | 2616 | 743k | for (auto& el : input_left) { | 2617 | 743k | el.sanity_check(); | 2618 | 743k | } | 2619 | 743k | for (auto& el : input_right) { | 2620 | 743k | el.sanity_check(); | 2621 | 743k | } | 2622 | 615k | for (auto& el : to_add) { | 2623 | 615k | el.sanity_check(); | 2624 | 615k | } | 2625 | 338k | input_quotient.sanity_check(); | 2626 | 338k | for (auto& el : input_remainders) { | 2627 | 338k | el.sanity_check(); | 2628 | 338k | } | 2629 | 338k | std::vector<bigfield> remainders(input_remainders); | 2630 | 338k | std::vector<bigfield> left(input_left); | 2631 | 338k | std::vector<bigfield> right(input_right); | 2632 | 338k | bigfield quotient = input_quotient; | 2633 | 338k | const size_t num_multiplications = input_left.size(); | 2634 | | | 2635 | 338k | Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context; | 2636 | | | 2637 | 338k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 338k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 338k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 338k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 338k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 338k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 338k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 338k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 338k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 338k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 338k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 338k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 338k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 338k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 338k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 338k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 338k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 338k | }; | 2656 | | | 2657 | | /** | 2658 | | * Step 1: Compute the maximum potential value of our product limbs | 2659 | | * | 2660 | | * max_lo = maximum value of limb products that span the range 0 - 2^{3t} | 2661 | | * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t} | 2662 | | * (t = NUM_LIMB_BITS) | 2663 | | **/ | 2664 | 338k | uint512_t max_lo = 0; | 2665 | 338k | uint512_t max_hi = 0; | 2666 | | | 2667 | | // Compute max values of quotient product limb products | 2668 | 338k | uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2669 | 338k | uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2670 | 338k | uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2671 | 338k | uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2672 | 338k | uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2673 | 338k | uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2674 | 338k | uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2675 | 338k | uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2676 | 338k | uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2677 | | | 2678 | | // max_r0 = terms from 0 - 2^2t | 2679 | | // max_r1 = terms from 2^t - 2^3t | 2680 | | // max_r2 = terms from 2^2t - 2^4t | 2681 | | // max_r3 = terms from 2^3t - 2^5t | 2682 | 338k | uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2683 | 338k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2684 | 338k | uint512_t max_r1 = max_b0 + max_b1; | 2685 | | | 2686 | 338k | uint256_t borrow_lo_value(0); | 2687 | 338k | for (const auto& remainder : input_remainders) { | 2688 | 338k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2689 | 338k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2690 | | | 2691 | 338k | borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value + | 2692 | 338k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2693 | 338k | } | 2694 | 338k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2695 | 338k | field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2696 | | | 2697 | 338k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2698 | 338k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2699 | | | 2700 | | // update max_lo, max_hi with quotient limb product terms. | 2701 | 338k | max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS); | 2702 | 338k | max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS); | 2703 | | | 2704 | | // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi | 2705 | 338k | uint512_t max_a0(0); | 2706 | 338k | uint512_t max_a1(0); | 2707 | 954k | for (size_t i = 0; i < to_add.size(); ++i) { | 2708 | 615k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2709 | 615k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2710 | 615k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2711 | 615k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2712 | 615k | } | 2713 | 338k | max_lo += max_a0; | 2714 | 338k | max_hi += max_a1; | 2715 | | | 2716 | | // Compute the maximum value of our multiplication products and add to max_lo, max_hi | 2717 | 1.08M | for (size_t i = 0; i < num_multiplications; ++i) { | 2718 | 743k | const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]); | 2719 | 743k | max_lo += product_lo; | 2720 | 743k | max_hi += product_hi; | 2721 | 743k | } | 2722 | | | 2723 | 338k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2724 | 338k | max_hi += max_lo_carry; | 2725 | | // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we | 2726 | | // will need to apply to validate our product | 2727 | 338k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2728 | 338k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2729 | | // Turbo range checks only work for even bit ranges, so make sure these values are even | 2730 | | // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges... | 2731 | 338k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2732 | 62.6k | ++max_lo_bits; | 2733 | 62.6k | } | 2734 | 338k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2735 | 307k | ++max_hi_bits; | 2736 | 307k | } | 2737 | | | 2738 | 338k | if constexpr (HasPlookup<Builder>) { | 2739 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2740 | | // If we're using constant values, instantiate them as circuit variables | 2741 | | | 2742 | 338k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 338k | bigfield output(input); | 2744 | 338k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 338k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 338k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 338k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 338k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 338k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 338k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 338k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 338k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 338k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 338k | output.context = ctx; | 2755 | 338k | return output; | 2756 | 338k | }; | 2757 | | | 2758 | | // evalaute a nnf mul and add into existing lohi output for our extra product terms | 2759 | | // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx | 2760 | | // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136} | 2761 | | // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values | 2762 | | // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication + | 2763 | | // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If | 2764 | | // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into | 2765 | | // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting | 2766 | | // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two | 2767 | | // calls to `evaluate_non_native_field_multiplication` | 2768 | 338k | std::vector<field_t<Builder>> limb_0_accumulator; | 2769 | 338k | std::vector<field_t<Builder>> limb_2_accumulator; | 2770 | 338k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2771 | | | 2772 | 1.08M | for (size_t i = 0; i < num_multiplications; ++i) { | 2773 | 743k | if (i == 0 && left[0].is_constant()) { | 2774 | 0 | left[0] = convert_constant_to_fixed_witness(left[0]); | 2775 | 0 | } | 2776 | 743k | if (i == 0 && right[0].is_constant()) { | 2777 | 1 | right[0] = convert_constant_to_fixed_witness(right[0]); | 2778 | 1 | } | 2779 | 743k | if (i > 0 && left[i].is_constant()) { | 2780 | 0 | left[i] = convert_constant_to_fixed_witness(left[i]); | 2781 | 0 | } | 2782 | 743k | if (i > 0 && right[i].is_constant()) { | 2783 | 0 | right[i] = convert_constant_to_fixed_witness(right[i]); | 2784 | 0 | } | 2785 | | | 2786 | 743k | if (i > 0) { | 2787 | 405k | bb::non_native_field_witnesses<bb::fr> mul_witnesses = { | 2788 | 405k | { | 2789 | 405k | left[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2790 | 405k | left[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2791 | 405k | left[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2792 | 405k | left[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2793 | 405k | }, | 2794 | 405k | { | 2795 | 405k | right[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2796 | 405k | right[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2797 | 405k | right[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2798 | 405k | right[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2799 | 405k | }, | 2800 | 405k | { | 2801 | 405k | ctx->zero_idx, | 2802 | 405k | ctx->zero_idx, | 2803 | 405k | ctx->zero_idx, | 2804 | 405k | ctx->zero_idx, | 2805 | 405k | }, | 2806 | 405k | { | 2807 | 405k | ctx->zero_idx, | 2808 | 405k | ctx->zero_idx, | 2809 | 405k | ctx->zero_idx, | 2810 | 405k | ctx->zero_idx, | 2811 | 405k | }, | 2812 | 405k | { 0, 0, 0, 0 }, | 2813 | 405k | modulus, | 2814 | 405k | }; | 2815 | | | 2816 | 405k | const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses); | 2817 | | | 2818 | 405k | field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx); | 2819 | 405k | field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx); | 2820 | | | 2821 | 405k | limb_0_accumulator.emplace_back(-lo_2); | 2822 | 405k | limb_2_accumulator.emplace_back(-hi_2); | 2823 | 405k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 2824 | 405k | } | 2825 | 743k | } | 2826 | 338k | if (quotient.is_constant()) { | 2827 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2828 | 0 | } | 2829 | | | 2830 | 338k | bool no_remainders = remainders.size() == 0; | 2831 | 338k | if (!no_remainders) { | 2832 | 338k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 2833 | 338k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 2834 | 338k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 2835 | 338k | } | 2836 | 338k | for (size_t i = 1; i < remainders.size(); ++i) { | 2837 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2838 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2839 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2840 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2841 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2842 | 0 | } | 2843 | 615k | for (const auto& add : to_add) { | 2844 | 615k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2845 | 615k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2846 | 615k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2847 | 615k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2848 | 615k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2849 | 615k | } | 2850 | | | 2851 | 338k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 2852 | 338k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 2853 | 338k | if (accumulated_lo.is_constant()) { | 2854 | 0 | accumulated_lo = | 2855 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 2856 | 0 | } | 2857 | 338k | if (accumulated_hi.is_constant()) { | 2858 | 0 | accumulated_hi = | 2859 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 2860 | 0 | } | 2861 | 338k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2862 | 338k | : remainders[0].binary_basis_limbs[1].element; | 2863 | 338k | if (remainder1.is_constant()) { | 2864 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 2865 | 0 | } | 2866 | 338k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2867 | 338k | : remainders[0].binary_basis_limbs[3].element; | 2868 | 338k | if (remainder3.is_constant()) { | 2869 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 2870 | 0 | } | 2871 | 338k | field_t<Builder> remainder_limbs[4]{ | 2872 | 338k | accumulated_lo, | 2873 | 338k | remainder1, | 2874 | 338k | accumulated_hi, | 2875 | 338k | remainder3, | 2876 | 338k | }; | 2877 | 338k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2878 | | | 2879 | 338k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2880 | 338k | { | 2881 | 338k | left[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2882 | 338k | left[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2883 | 338k | left[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2884 | 338k | left[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2885 | 338k | }, | 2886 | 338k | { | 2887 | 338k | right[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2888 | 338k | right[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2889 | 338k | right[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2890 | 338k | right[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2891 | 338k | }, | 2892 | 338k | { | 2893 | 338k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2894 | 338k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2895 | 338k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2896 | 338k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2897 | 338k | }, | 2898 | 338k | { | 2899 | 338k | remainder_limbs[0].get_normalized_witness_index(), | 2900 | 338k | remainder_limbs[1].get_normalized_witness_index(), | 2901 | 338k | remainder_limbs[2].get_normalized_witness_index(), | 2902 | 338k | remainder_limbs[3].get_normalized_witness_index(), | 2903 | 338k | }, | 2904 | 338k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2905 | 338k | modulus, | 2906 | 338k | }; | 2907 | | | 2908 | 338k | const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2909 | | | 2910 | 338k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2911 | | | 2912 | 338k | field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb, | 2913 | 338k | right[0].prime_basis_limb, | 2914 | 338k | quotient.prime_basis_limb * neg_prime, | 2915 | 338k | -remainder_prime_limb); | 2916 | | | 2917 | 338k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo; | 2918 | 338k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx); | 2919 | | | 2920 | 338k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2921 | 338k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2922 | | | 2923 | 338k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2924 | 0 | carry_lo_msb = 0; | 2925 | 0 | } | 2926 | 338k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2927 | 0 | carry_hi_msb = 0; | 2928 | 0 | } | 2929 | | | 2930 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2931 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2932 | 338k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2933 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2934 | 0 | lo.get_normalized_witness_index(), | 2935 | 0 | (size_t)carry_hi_msb, | 2936 | 0 | (size_t)carry_lo_msb); | 2937 | 338k | } else { | 2938 | 338k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2939 | 338k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2940 | 338k | } | 2941 | | /* NOTE TO AUDITOR: An extraneous block | 2942 | | if constexpr (HasPlookup<Builder>) { | 2943 | | carry_lo = carry_lo.normalize(); | 2944 | | carry_hi = carry_hi.normalize(); | 2945 | | ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb)); | 2946 | | ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb)); | 2947 | | } | 2948 | | was removed from the `else` block below. See the conversation at | 2949 | | https://github.com/AztecProtocol/aztec2-internal/pull/1023 | 2950 | | We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint | 2951 | | was just imposed?). */ | 2952 | 338k | } else { | 2953 | 338k | field_t b0 = left[0].binary_basis_limbs[1].element.madd( | 2954 | 338k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2955 | 338k | field_t b1 = left[0].binary_basis_limbs[0].element.madd( | 2956 | 338k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2957 | 338k | field_t c0 = left[0].binary_basis_limbs[1].element.madd( | 2958 | 338k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2959 | 338k | field_t c1 = left[0].binary_basis_limbs[2].element.madd( | 2960 | 338k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2961 | 338k | field_t c2 = left[0].binary_basis_limbs[0].element.madd( | 2962 | 338k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2963 | 338k | field_t d0 = left[0].binary_basis_limbs[3].element.madd( | 2964 | 338k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2965 | 338k | field_t d1 = left[0].binary_basis_limbs[2].element.madd( | 2966 | 338k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2967 | 338k | field_t d2 = left[0].binary_basis_limbs[1].element.madd( | 2968 | 338k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2969 | 338k | field_t d3 = left[0].binary_basis_limbs[0].element.madd( | 2970 | 338k | right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2971 | | | 2972 | | /** | 2973 | | * Compute "limb accumulators" | 2974 | | * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t} | 2975 | | * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS) | 2976 | | * Actual range will vary a few bits because of lazy reduction techniques | 2977 | | * | 2978 | | * We store these values in an "accumulator" vector in order to efficiently add them into a sum. | 2979 | | * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator) | 2980 | | * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single | 2981 | | * custom gate. | 2982 | | **/ | 2983 | | | 2984 | 338k | std::vector<field_t<Builder>> limb_0_accumulator; | 2985 | 338k | std::vector<field_t<Builder>> limb_2_accumulator; | 2986 | 338k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2987 | | | 2988 | | // Add remaining products into the limb accumulators. | 2989 | | // We negate the product values because the accumulator values itself will be negated | 2990 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 2991 | | // that the accumulators originaly tracked the remainder term (which is negated) | 2992 | | | 2993 | 338k | for (size_t i = 1; i < num_multiplications; ++i) { | 2994 | 338k | field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element; | 2995 | 338k | lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2); | 2996 | 338k | lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2); | 2997 | 338k | field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element; | 2998 | 338k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2); | 2999 | 338k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2); | 3000 | 338k | hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2); | 3001 | 338k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2); | 3002 | 338k | hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2); | 3003 | 338k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2); | 3004 | | | 3005 | 338k | limb_0_accumulator.emplace_back(-lo_2); | 3006 | 338k | limb_2_accumulator.emplace_back(-hi_2); | 3007 | 338k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 3008 | 338k | } | 3009 | | // add cached products into the limb accumulators. | 3010 | | // We negate the cache values because the accumulator values itself will be negated | 3011 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 3012 | | // that the accumulators originaly tracked the remainder term (which is negated) | 3013 | | | 3014 | | // Update the accumulators with the remainder terms. First check we actually have remainder terms! | 3015 | | //(not present when we're checking a product is 0 mod p). See `assert_is_in_field` | 3016 | | | 3017 | 338k | bool no_remainders = remainders.size() == 0; | 3018 | 338k | if (!no_remainders) { | 3019 | 338k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 3020 | 338k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 3021 | 338k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 3022 | 338k | } | 3023 | 338k | for (size_t i = 1; i < remainders.size(); ++i) { | 3024 | 338k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 3025 | 338k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 3026 | 338k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 3027 | 338k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 3028 | 338k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 3029 | 338k | } | 3030 | 338k | for (const auto& add : to_add) { | 3031 | 338k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 3032 | 338k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 3033 | 338k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 3034 | 338k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 3035 | 338k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 3036 | 338k | } | 3037 | | | 3038 | 338k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 3039 | 338k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 3040 | 338k | if (accumulated_lo.is_constant()) { | 3041 | 338k | accumulated_lo = | 3042 | 338k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 3043 | 338k | } | 3044 | 338k | if (accumulated_hi.is_constant()) { | 3045 | 338k | accumulated_hi = | 3046 | 338k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 3047 | 338k | } | 3048 | 338k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3049 | 338k | : remainders[0].binary_basis_limbs[1].element; | 3050 | 338k | if (remainder1.is_constant()) { | 3051 | 338k | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 3052 | 338k | } | 3053 | 338k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3054 | 338k | : remainders[0].binary_basis_limbs[3].element; | 3055 | 338k | if (remainder3.is_constant()) { | 3056 | 338k | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 3057 | 338k | } | 3058 | 338k | field_t<Builder> remainder_limbs[4]{ | 3059 | 338k | accumulated_lo, | 3060 | 338k | remainder1, | 3061 | 338k | accumulated_hi, | 3062 | 338k | remainder3, | 3063 | 338k | }; | 3064 | 338k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 3065 | | | 3066 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 3067 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 3068 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 3069 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 3070 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 3071 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 3072 | | | 3073 | 338k | field_t r0 = left[0].binary_basis_limbs[0].element.madd( | 3074 | 338k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3075 | 338k | field_t r1 = b0.add_two(b1, -remainder_limbs[1]); | 3076 | 338k | const field_t r2 = c0.add_two(c1, c2); | 3077 | 338k | const field_t r3 = d0 + d1.add_two(d2, d3); | 3078 | | | 3079 | 338k | field_t carry_lo_0 = r0 * shift_right_2; | 3080 | 338k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3081 | 338k | field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2); | 3082 | 338k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3083 | | | 3084 | 338k | field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1)); | 3085 | 338k | carry_lo += borrow_lo; | 3086 | 338k | field_t carry_hi_0 = r2 * shift_right_2; | 3087 | 338k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3088 | 338k | field_t carry_hi_2 = t1 * shift_right_2; | 3089 | 338k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3090 | | | 3091 | 338k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3092 | | | 3093 | 338k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 3094 | | | 3095 | 338k | linear_terms += -remainder_prime_limb; | 3096 | | | 3097 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 3098 | 338k | field_t<Builder>::evaluate_polynomial_identity( | 3099 | 338k | left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3100 | | | 3101 | 338k | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3102 | 338k | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3103 | | | 3104 | 338k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3105 | | | 3106 | 338k | if constexpr (HasPlookup<Builder>) { | 3107 | 338k | carry_lo = carry_lo.normalize(); | 3108 | 338k | carry_hi = carry_hi.normalize(); | 3109 | 338k | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), | 3110 | 338k | static_cast<size_t>(carry_lo_msb)); | 3111 | 338k | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), | 3112 | 338k | static_cast<size_t>(carry_hi_msb)); | 3113 | | | 3114 | 338k | } else { | 3115 | 338k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3116 | 338k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3117 | 338k | carry_combined = carry_combined.normalize(); | 3118 | 338k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3119 | 338k | carry_combined.get_normalized_witness_index(), | 3120 | 338k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3121 | 338k | "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add."); | 3122 | 338k | field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index( | 3123 | 338k | ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3124 | 338k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3125 | 338k | } else { | 3126 | 338k | carry_lo = carry_lo.normalize(); | 3127 | 338k | carry_hi = carry_hi.normalize(); | 3128 | 338k | ctx->decompose_into_base4_accumulators( | 3129 | 338k | carry_lo.get_normalized_witness_index(), | 3130 | 338k | static_cast<size_t>(carry_lo_msb), | 3131 | 338k | "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add."); | 3132 | 338k | ctx->decompose_into_base4_accumulators( | 3133 | 338k | carry_hi.get_normalized_witness_index(), | 3134 | 338k | static_cast<size_t>(carry_hi_msb), | 3135 | 338k | "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add."); | 3136 | 338k | } | 3137 | 338k | } | 3138 | 338k | } | 3139 | 338k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ Line | Count | Source | 2608 | 1.29k | { | 2609 | 1.29k | ASSERT(input_left.size() == input_right.size()); | 2610 | 1.29k | ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT); | 2611 | 1.29k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2612 | 1.29k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2613 | | | 2614 | 1.29k | ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024); | 2615 | | // Sanity checks | 2616 | 3.15k | for (auto& el : input_left) { | 2617 | 3.15k | el.sanity_check(); | 2618 | 3.15k | } | 2619 | 3.15k | for (auto& el : input_right) { | 2620 | 3.15k | el.sanity_check(); | 2621 | 3.15k | } | 2622 | 1.37k | for (auto& el : to_add) { | 2623 | 1.37k | el.sanity_check(); | 2624 | 1.37k | } | 2625 | 1.29k | input_quotient.sanity_check(); | 2626 | 1.29k | for (auto& el : input_remainders) { | 2627 | 1.29k | el.sanity_check(); | 2628 | 1.29k | } | 2629 | 1.29k | std::vector<bigfield> remainders(input_remainders); | 2630 | 1.29k | std::vector<bigfield> left(input_left); | 2631 | 1.29k | std::vector<bigfield> right(input_right); | 2632 | 1.29k | bigfield quotient = input_quotient; | 2633 | 1.29k | const size_t num_multiplications = input_left.size(); | 2634 | | | 2635 | 1.29k | Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context; | 2636 | | | 2637 | 1.29k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 1.29k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 1.29k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 1.29k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 1.29k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 1.29k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 1.29k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 1.29k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 1.29k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 1.29k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 1.29k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 1.29k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 1.29k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 1.29k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 1.29k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 1.29k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 1.29k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 1.29k | }; | 2656 | | | 2657 | | /** | 2658 | | * Step 1: Compute the maximum potential value of our product limbs | 2659 | | * | 2660 | | * max_lo = maximum value of limb products that span the range 0 - 2^{3t} | 2661 | | * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t} | 2662 | | * (t = NUM_LIMB_BITS) | 2663 | | **/ | 2664 | 1.29k | uint512_t max_lo = 0; | 2665 | 1.29k | uint512_t max_hi = 0; | 2666 | | | 2667 | | // Compute max values of quotient product limb products | 2668 | 1.29k | uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2669 | 1.29k | uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2670 | 1.29k | uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2671 | 1.29k | uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2672 | 1.29k | uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2673 | 1.29k | uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2674 | 1.29k | uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2675 | 1.29k | uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2676 | 1.29k | uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2677 | | | 2678 | | // max_r0 = terms from 0 - 2^2t | 2679 | | // max_r1 = terms from 2^t - 2^3t | 2680 | | // max_r2 = terms from 2^2t - 2^4t | 2681 | | // max_r3 = terms from 2^3t - 2^5t | 2682 | 1.29k | uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2683 | 1.29k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2684 | 1.29k | uint512_t max_r1 = max_b0 + max_b1; | 2685 | | | 2686 | 1.29k | uint256_t borrow_lo_value(0); | 2687 | 1.29k | for (const auto& remainder : input_remainders) { | 2688 | 1.29k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2689 | 1.29k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2690 | | | 2691 | 1.29k | borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value + | 2692 | 1.29k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2693 | 1.29k | } | 2694 | 1.29k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2695 | 1.29k | field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2696 | | | 2697 | 1.29k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2698 | 1.29k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2699 | | | 2700 | | // update max_lo, max_hi with quotient limb product terms. | 2701 | 1.29k | max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS); | 2702 | 1.29k | max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS); | 2703 | | | 2704 | | // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi | 2705 | 1.29k | uint512_t max_a0(0); | 2706 | 1.29k | uint512_t max_a1(0); | 2707 | 2.66k | for (size_t i = 0; i < to_add.size(); ++i) { | 2708 | 1.37k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2709 | 1.37k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2710 | 1.37k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2711 | 1.37k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2712 | 1.37k | } | 2713 | 1.29k | max_lo += max_a0; | 2714 | 1.29k | max_hi += max_a1; | 2715 | | | 2716 | | // Compute the maximum value of our multiplication products and add to max_lo, max_hi | 2717 | 4.44k | for (size_t i = 0; i < num_multiplications; ++i) { | 2718 | 3.15k | const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]); | 2719 | 3.15k | max_lo += product_lo; | 2720 | 3.15k | max_hi += product_hi; | 2721 | 3.15k | } | 2722 | | | 2723 | 1.29k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2724 | 1.29k | max_hi += max_lo_carry; | 2725 | | // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we | 2726 | | // will need to apply to validate our product | 2727 | 1.29k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2728 | 1.29k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2729 | | // Turbo range checks only work for even bit ranges, so make sure these values are even | 2730 | | // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges... | 2731 | 1.29k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2732 | 585 | ++max_lo_bits; | 2733 | 585 | } | 2734 | 1.29k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2735 | 594 | ++max_hi_bits; | 2736 | 594 | } | 2737 | | | 2738 | 1.29k | if constexpr (HasPlookup<Builder>) { | 2739 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2740 | | // If we're using constant values, instantiate them as circuit variables | 2741 | | | 2742 | 1.29k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 1.29k | bigfield output(input); | 2744 | 1.29k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 1.29k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 1.29k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 1.29k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 1.29k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 1.29k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 1.29k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 1.29k | output.context = ctx; | 2755 | 1.29k | return output; | 2756 | 1.29k | }; | 2757 | | | 2758 | | // evalaute a nnf mul and add into existing lohi output for our extra product terms | 2759 | | // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx | 2760 | | // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136} | 2761 | | // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values | 2762 | | // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication + | 2763 | | // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If | 2764 | | // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into | 2765 | | // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting | 2766 | | // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two | 2767 | | // calls to `evaluate_non_native_field_multiplication` | 2768 | 1.29k | std::vector<field_t<Builder>> limb_0_accumulator; | 2769 | 1.29k | std::vector<field_t<Builder>> limb_2_accumulator; | 2770 | 1.29k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2771 | | | 2772 | 4.44k | for (size_t i = 0; i < num_multiplications; ++i) { | 2773 | 3.15k | if (i == 0 && left[0].is_constant()) { | 2774 | 0 | left[0] = convert_constant_to_fixed_witness(left[0]); | 2775 | 0 | } | 2776 | 3.15k | if (i == 0 && right[0].is_constant()) { | 2777 | 0 | right[0] = convert_constant_to_fixed_witness(right[0]); | 2778 | 0 | } | 2779 | 3.15k | if (i > 0 && left[i].is_constant()) { | 2780 | 0 | left[i] = convert_constant_to_fixed_witness(left[i]); | 2781 | 0 | } | 2782 | 3.15k | if (i > 0 && right[i].is_constant()) { | 2783 | 0 | right[i] = convert_constant_to_fixed_witness(right[i]); | 2784 | 0 | } | 2785 | | | 2786 | 3.15k | if (i > 0) { | 2787 | 1.86k | bb::non_native_field_witnesses<bb::fr> mul_witnesses = { | 2788 | 1.86k | { | 2789 | 1.86k | left[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2790 | 1.86k | left[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2791 | 1.86k | left[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2792 | 1.86k | left[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2793 | 1.86k | }, | 2794 | 1.86k | { | 2795 | 1.86k | right[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2796 | 1.86k | right[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2797 | 1.86k | right[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2798 | 1.86k | right[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2799 | 1.86k | }, | 2800 | 1.86k | { | 2801 | 1.86k | ctx->zero_idx, | 2802 | 1.86k | ctx->zero_idx, | 2803 | 1.86k | ctx->zero_idx, | 2804 | 1.86k | ctx->zero_idx, | 2805 | 1.86k | }, | 2806 | 1.86k | { | 2807 | 1.86k | ctx->zero_idx, | 2808 | 1.86k | ctx->zero_idx, | 2809 | 1.86k | ctx->zero_idx, | 2810 | 1.86k | ctx->zero_idx, | 2811 | 1.86k | }, | 2812 | 1.86k | { 0, 0, 0, 0 }, | 2813 | 1.86k | modulus, | 2814 | 1.86k | }; | 2815 | | | 2816 | 1.86k | const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses); | 2817 | | | 2818 | 1.86k | field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx); | 2819 | 1.86k | field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx); | 2820 | | | 2821 | 1.86k | limb_0_accumulator.emplace_back(-lo_2); | 2822 | 1.86k | limb_2_accumulator.emplace_back(-hi_2); | 2823 | 1.86k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 2824 | 1.86k | } | 2825 | 3.15k | } | 2826 | 1.29k | if (quotient.is_constant()) { | 2827 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2828 | 0 | } | 2829 | | | 2830 | 1.29k | bool no_remainders = remainders.size() == 0; | 2831 | 1.29k | if (!no_remainders) { | 2832 | 1.29k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 2833 | 1.29k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 2834 | 1.29k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 2835 | 1.29k | } | 2836 | 1.29k | for (size_t i = 1; i < remainders.size(); ++i) { | 2837 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2838 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2839 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2840 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2841 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2842 | 0 | } | 2843 | 1.37k | for (const auto& add : to_add) { | 2844 | 1.37k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2845 | 1.37k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2846 | 1.37k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2847 | 1.37k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2848 | 1.37k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2849 | 1.37k | } | 2850 | | | 2851 | 1.29k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 2852 | 1.29k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 2853 | 1.29k | if (accumulated_lo.is_constant()) { | 2854 | 0 | accumulated_lo = | 2855 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 2856 | 0 | } | 2857 | 1.29k | if (accumulated_hi.is_constant()) { | 2858 | 0 | accumulated_hi = | 2859 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 2860 | 0 | } | 2861 | 1.29k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2862 | 1.29k | : remainders[0].binary_basis_limbs[1].element; | 2863 | 1.29k | if (remainder1.is_constant()) { | 2864 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 2865 | 0 | } | 2866 | 1.29k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2867 | 1.29k | : remainders[0].binary_basis_limbs[3].element; | 2868 | 1.29k | if (remainder3.is_constant()) { | 2869 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 2870 | 0 | } | 2871 | 1.29k | field_t<Builder> remainder_limbs[4]{ | 2872 | 1.29k | accumulated_lo, | 2873 | 1.29k | remainder1, | 2874 | 1.29k | accumulated_hi, | 2875 | 1.29k | remainder3, | 2876 | 1.29k | }; | 2877 | 1.29k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2878 | | | 2879 | 1.29k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2880 | 1.29k | { | 2881 | 1.29k | left[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2882 | 1.29k | left[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2883 | 1.29k | left[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2884 | 1.29k | left[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2885 | 1.29k | }, | 2886 | 1.29k | { | 2887 | 1.29k | right[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2888 | 1.29k | right[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2889 | 1.29k | right[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2890 | 1.29k | right[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2891 | 1.29k | }, | 2892 | 1.29k | { | 2893 | 1.29k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2894 | 1.29k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2895 | 1.29k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2896 | 1.29k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2897 | 1.29k | }, | 2898 | 1.29k | { | 2899 | 1.29k | remainder_limbs[0].get_normalized_witness_index(), | 2900 | 1.29k | remainder_limbs[1].get_normalized_witness_index(), | 2901 | 1.29k | remainder_limbs[2].get_normalized_witness_index(), | 2902 | 1.29k | remainder_limbs[3].get_normalized_witness_index(), | 2903 | 1.29k | }, | 2904 | 1.29k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2905 | 1.29k | modulus, | 2906 | 1.29k | }; | 2907 | | | 2908 | 1.29k | const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2909 | | | 2910 | 1.29k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2911 | | | 2912 | 1.29k | field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb, | 2913 | 1.29k | right[0].prime_basis_limb, | 2914 | 1.29k | quotient.prime_basis_limb * neg_prime, | 2915 | 1.29k | -remainder_prime_limb); | 2916 | | | 2917 | 1.29k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo; | 2918 | 1.29k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx); | 2919 | | | 2920 | 1.29k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2921 | 1.29k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2922 | | | 2923 | 1.29k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2924 | 0 | carry_lo_msb = 0; | 2925 | 0 | } | 2926 | 1.29k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2927 | 0 | carry_hi_msb = 0; | 2928 | 0 | } | 2929 | | | 2930 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2931 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2932 | 1.29k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2933 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2934 | 0 | lo.get_normalized_witness_index(), | 2935 | 0 | (size_t)carry_hi_msb, | 2936 | 0 | (size_t)carry_lo_msb); | 2937 | 1.29k | } else { | 2938 | 1.29k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2939 | 1.29k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2940 | 1.29k | } | 2941 | | /* NOTE TO AUDITOR: An extraneous block | 2942 | | if constexpr (HasPlookup<Builder>) { | 2943 | | carry_lo = carry_lo.normalize(); | 2944 | | carry_hi = carry_hi.normalize(); | 2945 | | ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb)); | 2946 | | ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb)); | 2947 | | } | 2948 | | was removed from the `else` block below. See the conversation at | 2949 | | https://github.com/AztecProtocol/aztec2-internal/pull/1023 | 2950 | | We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint | 2951 | | was just imposed?). */ | 2952 | 1.29k | } else { | 2953 | 1.29k | field_t b0 = left[0].binary_basis_limbs[1].element.madd( | 2954 | 1.29k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2955 | 1.29k | field_t b1 = left[0].binary_basis_limbs[0].element.madd( | 2956 | 1.29k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2957 | 1.29k | field_t c0 = left[0].binary_basis_limbs[1].element.madd( | 2958 | 1.29k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2959 | 1.29k | field_t c1 = left[0].binary_basis_limbs[2].element.madd( | 2960 | 1.29k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2961 | 1.29k | field_t c2 = left[0].binary_basis_limbs[0].element.madd( | 2962 | 1.29k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2963 | 1.29k | field_t d0 = left[0].binary_basis_limbs[3].element.madd( | 2964 | 1.29k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2965 | 1.29k | field_t d1 = left[0].binary_basis_limbs[2].element.madd( | 2966 | 1.29k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2967 | 1.29k | field_t d2 = left[0].binary_basis_limbs[1].element.madd( | 2968 | 1.29k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2969 | 1.29k | field_t d3 = left[0].binary_basis_limbs[0].element.madd( | 2970 | 1.29k | right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2971 | | | 2972 | | /** | 2973 | | * Compute "limb accumulators" | 2974 | | * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t} | 2975 | | * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS) | 2976 | | * Actual range will vary a few bits because of lazy reduction techniques | 2977 | | * | 2978 | | * We store these values in an "accumulator" vector in order to efficiently add them into a sum. | 2979 | | * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator) | 2980 | | * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single | 2981 | | * custom gate. | 2982 | | **/ | 2983 | | | 2984 | 1.29k | std::vector<field_t<Builder>> limb_0_accumulator; | 2985 | 1.29k | std::vector<field_t<Builder>> limb_2_accumulator; | 2986 | 1.29k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2987 | | | 2988 | | // Add remaining products into the limb accumulators. | 2989 | | // We negate the product values because the accumulator values itself will be negated | 2990 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 2991 | | // that the accumulators originaly tracked the remainder term (which is negated) | 2992 | | | 2993 | 1.29k | for (size_t i = 1; i < num_multiplications; ++i) { | 2994 | 1.29k | field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element; | 2995 | 1.29k | lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2); | 2996 | 1.29k | lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2); | 2997 | 1.29k | field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element; | 2998 | 1.29k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2); | 2999 | 1.29k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2); | 3000 | 1.29k | hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2); | 3001 | 1.29k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2); | 3002 | 1.29k | hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2); | 3003 | 1.29k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2); | 3004 | | | 3005 | 1.29k | limb_0_accumulator.emplace_back(-lo_2); | 3006 | 1.29k | limb_2_accumulator.emplace_back(-hi_2); | 3007 | 1.29k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 3008 | 1.29k | } | 3009 | | // add cached products into the limb accumulators. | 3010 | | // We negate the cache values because the accumulator values itself will be negated | 3011 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 3012 | | // that the accumulators originaly tracked the remainder term (which is negated) | 3013 | | | 3014 | | // Update the accumulators with the remainder terms. First check we actually have remainder terms! | 3015 | | //(not present when we're checking a product is 0 mod p). See `assert_is_in_field` | 3016 | | | 3017 | 1.29k | bool no_remainders = remainders.size() == 0; | 3018 | 1.29k | if (!no_remainders) { | 3019 | 1.29k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 3020 | 1.29k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 3021 | 1.29k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 3022 | 1.29k | } | 3023 | 1.29k | for (size_t i = 1; i < remainders.size(); ++i) { | 3024 | 1.29k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 3025 | 1.29k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 3026 | 1.29k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 3027 | 1.29k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 3028 | 1.29k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 3029 | 1.29k | } | 3030 | 1.29k | for (const auto& add : to_add) { | 3031 | 1.29k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 3032 | 1.29k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 3033 | 1.29k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 3034 | 1.29k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 3035 | 1.29k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 3036 | 1.29k | } | 3037 | | | 3038 | 1.29k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 3039 | 1.29k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 3040 | 1.29k | if (accumulated_lo.is_constant()) { | 3041 | 1.29k | accumulated_lo = | 3042 | 1.29k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 3043 | 1.29k | } | 3044 | 1.29k | if (accumulated_hi.is_constant()) { | 3045 | 1.29k | accumulated_hi = | 3046 | 1.29k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 3047 | 1.29k | } | 3048 | 1.29k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3049 | 1.29k | : remainders[0].binary_basis_limbs[1].element; | 3050 | 1.29k | if (remainder1.is_constant()) { | 3051 | 1.29k | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 3052 | 1.29k | } | 3053 | 1.29k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3054 | 1.29k | : remainders[0].binary_basis_limbs[3].element; | 3055 | 1.29k | if (remainder3.is_constant()) { | 3056 | 1.29k | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 3057 | 1.29k | } | 3058 | 1.29k | field_t<Builder> remainder_limbs[4]{ | 3059 | 1.29k | accumulated_lo, | 3060 | 1.29k | remainder1, | 3061 | 1.29k | accumulated_hi, | 3062 | 1.29k | remainder3, | 3063 | 1.29k | }; | 3064 | 1.29k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 3065 | | | 3066 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 3067 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 3068 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 3069 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 3070 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 3071 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 3072 | | | 3073 | 1.29k | field_t r0 = left[0].binary_basis_limbs[0].element.madd( | 3074 | 1.29k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3075 | 1.29k | field_t r1 = b0.add_two(b1, -remainder_limbs[1]); | 3076 | 1.29k | const field_t r2 = c0.add_two(c1, c2); | 3077 | 1.29k | const field_t r3 = d0 + d1.add_two(d2, d3); | 3078 | | | 3079 | 1.29k | field_t carry_lo_0 = r0 * shift_right_2; | 3080 | 1.29k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3081 | 1.29k | field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2); | 3082 | 1.29k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3083 | | | 3084 | 1.29k | field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1)); | 3085 | 1.29k | carry_lo += borrow_lo; | 3086 | 1.29k | field_t carry_hi_0 = r2 * shift_right_2; | 3087 | 1.29k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3088 | 1.29k | field_t carry_hi_2 = t1 * shift_right_2; | 3089 | 1.29k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3090 | | | 3091 | 1.29k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3092 | | | 3093 | 1.29k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 3094 | | | 3095 | 1.29k | linear_terms += -remainder_prime_limb; | 3096 | | | 3097 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 3098 | 1.29k | field_t<Builder>::evaluate_polynomial_identity( | 3099 | 1.29k | left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3100 | | | 3101 | 1.29k | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3102 | 1.29k | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3103 | | | 3104 | 1.29k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3105 | | | 3106 | 1.29k | if constexpr (HasPlookup<Builder>) { | 3107 | 1.29k | carry_lo = carry_lo.normalize(); | 3108 | 1.29k | carry_hi = carry_hi.normalize(); | 3109 | 1.29k | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), | 3110 | 1.29k | static_cast<size_t>(carry_lo_msb)); | 3111 | 1.29k | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), | 3112 | 1.29k | static_cast<size_t>(carry_hi_msb)); | 3113 | | | 3114 | 1.29k | } else { | 3115 | 1.29k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3116 | 1.29k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3117 | 1.29k | carry_combined = carry_combined.normalize(); | 3118 | 1.29k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3119 | 1.29k | carry_combined.get_normalized_witness_index(), | 3120 | 1.29k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3121 | 1.29k | "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add."); | 3122 | 1.29k | field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index( | 3123 | 1.29k | ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3124 | 1.29k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3125 | 1.29k | } else { | 3126 | 1.29k | carry_lo = carry_lo.normalize(); | 3127 | 1.29k | carry_hi = carry_hi.normalize(); | 3128 | 1.29k | ctx->decompose_into_base4_accumulators( | 3129 | 1.29k | carry_lo.get_normalized_witness_index(), | 3130 | 1.29k | static_cast<size_t>(carry_lo_msb), | 3131 | 1.29k | "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add."); | 3132 | 1.29k | ctx->decompose_into_base4_accumulators( | 3133 | 1.29k | carry_hi.get_normalized_witness_index(), | 3134 | 1.29k | static_cast<size_t>(carry_hi_msb), | 3135 | 1.29k | "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add."); | 3136 | 1.29k | } | 3137 | 1.29k | } | 3138 | 1.29k | } | 3139 | 1.29k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ Line | Count | Source | 2608 | 28.3k | { | 2609 | 28.3k | ASSERT(input_left.size() == input_right.size()); | 2610 | 28.3k | ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT); | 2611 | 28.3k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2612 | 28.3k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2613 | | | 2614 | 28.3k | ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024); | 2615 | | // Sanity checks | 2616 | 70.5k | for (auto& el : input_left) { | 2617 | 70.5k | el.sanity_check(); | 2618 | 70.5k | } | 2619 | 70.5k | for (auto& el : input_right) { | 2620 | 70.5k | el.sanity_check(); | 2621 | 70.5k | } | 2622 | 33.1k | for (auto& el : to_add) { | 2623 | 33.1k | el.sanity_check(); | 2624 | 33.1k | } | 2625 | 28.3k | input_quotient.sanity_check(); | 2626 | 28.3k | for (auto& el : input_remainders) { | 2627 | 28.3k | el.sanity_check(); | 2628 | 28.3k | } | 2629 | 28.3k | std::vector<bigfield> remainders(input_remainders); | 2630 | 28.3k | std::vector<bigfield> left(input_left); | 2631 | 28.3k | std::vector<bigfield> right(input_right); | 2632 | 28.3k | bigfield quotient = input_quotient; | 2633 | 28.3k | const size_t num_multiplications = input_left.size(); | 2634 | | | 2635 | 28.3k | Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context; | 2636 | | | 2637 | 28.3k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 28.3k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 28.3k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 28.3k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 28.3k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 28.3k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 28.3k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 28.3k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 28.3k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 28.3k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 28.3k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 28.3k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 28.3k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 28.3k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 28.3k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 28.3k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 28.3k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 28.3k | }; | 2656 | | | 2657 | | /** | 2658 | | * Step 1: Compute the maximum potential value of our product limbs | 2659 | | * | 2660 | | * max_lo = maximum value of limb products that span the range 0 - 2^{3t} | 2661 | | * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t} | 2662 | | * (t = NUM_LIMB_BITS) | 2663 | | **/ | 2664 | 28.3k | uint512_t max_lo = 0; | 2665 | 28.3k | uint512_t max_hi = 0; | 2666 | | | 2667 | | // Compute max values of quotient product limb products | 2668 | 28.3k | uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2669 | 28.3k | uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2670 | 28.3k | uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2671 | 28.3k | uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2672 | 28.3k | uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2673 | 28.3k | uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2674 | 28.3k | uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2675 | 28.3k | uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2676 | 28.3k | uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2677 | | | 2678 | | // max_r0 = terms from 0 - 2^2t | 2679 | | // max_r1 = terms from 2^t - 2^3t | 2680 | | // max_r2 = terms from 2^2t - 2^4t | 2681 | | // max_r3 = terms from 2^3t - 2^5t | 2682 | 28.3k | uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2683 | 28.3k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2684 | 28.3k | uint512_t max_r1 = max_b0 + max_b1; | 2685 | | | 2686 | 28.3k | uint256_t borrow_lo_value(0); | 2687 | 28.3k | for (const auto& remainder : input_remainders) { | 2688 | 28.3k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2689 | 28.3k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2690 | | | 2691 | 28.3k | borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value + | 2692 | 28.3k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2693 | 28.3k | } | 2694 | 28.3k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2695 | 28.3k | field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2696 | | | 2697 | 28.3k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2698 | 28.3k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2699 | | | 2700 | | // update max_lo, max_hi with quotient limb product terms. | 2701 | 28.3k | max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS); | 2702 | 28.3k | max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS); | 2703 | | | 2704 | | // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi | 2705 | 28.3k | uint512_t max_a0(0); | 2706 | 28.3k | uint512_t max_a1(0); | 2707 | 61.4k | for (size_t i = 0; i < to_add.size(); ++i) { | 2708 | 33.1k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2709 | 33.1k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2710 | 33.1k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2711 | 33.1k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2712 | 33.1k | } | 2713 | 28.3k | max_lo += max_a0; | 2714 | 28.3k | max_hi += max_a1; | 2715 | | | 2716 | | // Compute the maximum value of our multiplication products and add to max_lo, max_hi | 2717 | 98.9k | for (size_t i = 0; i < num_multiplications; ++i) { | 2718 | 70.5k | const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]); | 2719 | 70.5k | max_lo += product_lo; | 2720 | 70.5k | max_hi += product_hi; | 2721 | 70.5k | } | 2722 | | | 2723 | 28.3k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2724 | 28.3k | max_hi += max_lo_carry; | 2725 | | // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we | 2726 | | // will need to apply to validate our product | 2727 | 28.3k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2728 | 28.3k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2729 | | // Turbo range checks only work for even bit ranges, so make sure these values are even | 2730 | | // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges... | 2731 | 28.3k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2732 | 14.1k | ++max_lo_bits; | 2733 | 14.1k | } | 2734 | 28.3k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2735 | 14.2k | ++max_hi_bits; | 2736 | 14.2k | } | 2737 | | | 2738 | 28.3k | if constexpr (HasPlookup<Builder>) { | 2739 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2740 | | // If we're using constant values, instantiate them as circuit variables | 2741 | | | 2742 | 28.3k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 28.3k | bigfield output(input); | 2744 | 28.3k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 28.3k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 28.3k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 28.3k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 28.3k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 28.3k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 28.3k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 28.3k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 28.3k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 28.3k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 28.3k | output.context = ctx; | 2755 | 28.3k | return output; | 2756 | 28.3k | }; | 2757 | | | 2758 | | // evalaute a nnf mul and add into existing lohi output for our extra product terms | 2759 | | // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx | 2760 | | // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136} | 2761 | | // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values | 2762 | | // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication + | 2763 | | // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If | 2764 | | // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into | 2765 | | // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting | 2766 | | // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two | 2767 | | // calls to `evaluate_non_native_field_multiplication` | 2768 | 28.3k | std::vector<field_t<Builder>> limb_0_accumulator; | 2769 | 28.3k | std::vector<field_t<Builder>> limb_2_accumulator; | 2770 | 28.3k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2771 | | | 2772 | 98.9k | for (size_t i = 0; i < num_multiplications; ++i) { | 2773 | 70.5k | if (i == 0 && left[0].is_constant()) { | 2774 | 0 | left[0] = convert_constant_to_fixed_witness(left[0]); | 2775 | 0 | } | 2776 | 70.5k | if (i == 0 && right[0].is_constant()) { | 2777 | 0 | right[0] = convert_constant_to_fixed_witness(right[0]); | 2778 | 0 | } | 2779 | 70.5k | if (i > 0 && left[i].is_constant()) { | 2780 | 0 | left[i] = convert_constant_to_fixed_witness(left[i]); | 2781 | 0 | } | 2782 | 70.5k | if (i > 0 && right[i].is_constant()) { | 2783 | 0 | right[i] = convert_constant_to_fixed_witness(right[i]); | 2784 | 0 | } | 2785 | | | 2786 | 70.5k | if (i > 0) { | 2787 | 42.1k | bb::non_native_field_witnesses<bb::fr> mul_witnesses = { | 2788 | 42.1k | { | 2789 | 42.1k | left[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2790 | 42.1k | left[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2791 | 42.1k | left[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2792 | 42.1k | left[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2793 | 42.1k | }, | 2794 | 42.1k | { | 2795 | 42.1k | right[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2796 | 42.1k | right[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2797 | 42.1k | right[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2798 | 42.1k | right[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2799 | 42.1k | }, | 2800 | 42.1k | { | 2801 | 42.1k | ctx->zero_idx, | 2802 | 42.1k | ctx->zero_idx, | 2803 | 42.1k | ctx->zero_idx, | 2804 | 42.1k | ctx->zero_idx, | 2805 | 42.1k | }, | 2806 | 42.1k | { | 2807 | 42.1k | ctx->zero_idx, | 2808 | 42.1k | ctx->zero_idx, | 2809 | 42.1k | ctx->zero_idx, | 2810 | 42.1k | ctx->zero_idx, | 2811 | 42.1k | }, | 2812 | 42.1k | { 0, 0, 0, 0 }, | 2813 | 42.1k | modulus, | 2814 | 42.1k | }; | 2815 | | | 2816 | 42.1k | const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses); | 2817 | | | 2818 | 42.1k | field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx); | 2819 | 42.1k | field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx); | 2820 | | | 2821 | 42.1k | limb_0_accumulator.emplace_back(-lo_2); | 2822 | 42.1k | limb_2_accumulator.emplace_back(-hi_2); | 2823 | 42.1k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 2824 | 42.1k | } | 2825 | 70.5k | } | 2826 | 28.3k | if (quotient.is_constant()) { | 2827 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2828 | 0 | } | 2829 | | | 2830 | 28.3k | bool no_remainders = remainders.size() == 0; | 2831 | 28.3k | if (!no_remainders) { | 2832 | 28.3k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 2833 | 28.3k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 2834 | 28.3k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 2835 | 28.3k | } | 2836 | 28.3k | for (size_t i = 1; i < remainders.size(); ++i) { | 2837 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2838 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2839 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2840 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2841 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2842 | 0 | } | 2843 | 33.1k | for (const auto& add : to_add) { | 2844 | 33.1k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2845 | 33.1k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2846 | 33.1k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2847 | 33.1k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2848 | 33.1k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2849 | 33.1k | } | 2850 | | | 2851 | 28.3k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 2852 | 28.3k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 2853 | 28.3k | if (accumulated_lo.is_constant()) { | 2854 | 0 | accumulated_lo = | 2855 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 2856 | 0 | } | 2857 | 28.3k | if (accumulated_hi.is_constant()) { | 2858 | 0 | accumulated_hi = | 2859 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 2860 | 0 | } | 2861 | 28.3k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2862 | 28.3k | : remainders[0].binary_basis_limbs[1].element; | 2863 | 28.3k | if (remainder1.is_constant()) { | 2864 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 2865 | 0 | } | 2866 | 28.3k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2867 | 28.3k | : remainders[0].binary_basis_limbs[3].element; | 2868 | 28.3k | if (remainder3.is_constant()) { | 2869 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 2870 | 0 | } | 2871 | 28.3k | field_t<Builder> remainder_limbs[4]{ | 2872 | 28.3k | accumulated_lo, | 2873 | 28.3k | remainder1, | 2874 | 28.3k | accumulated_hi, | 2875 | 28.3k | remainder3, | 2876 | 28.3k | }; | 2877 | 28.3k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2878 | | | 2879 | 28.3k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2880 | 28.3k | { | 2881 | 28.3k | left[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2882 | 28.3k | left[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2883 | 28.3k | left[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2884 | 28.3k | left[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2885 | 28.3k | }, | 2886 | 28.3k | { | 2887 | 28.3k | right[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2888 | 28.3k | right[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2889 | 28.3k | right[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2890 | 28.3k | right[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2891 | 28.3k | }, | 2892 | 28.3k | { | 2893 | 28.3k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2894 | 28.3k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2895 | 28.3k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2896 | 28.3k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2897 | 28.3k | }, | 2898 | 28.3k | { | 2899 | 28.3k | remainder_limbs[0].get_normalized_witness_index(), | 2900 | 28.3k | remainder_limbs[1].get_normalized_witness_index(), | 2901 | 28.3k | remainder_limbs[2].get_normalized_witness_index(), | 2902 | 28.3k | remainder_limbs[3].get_normalized_witness_index(), | 2903 | 28.3k | }, | 2904 | 28.3k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2905 | 28.3k | modulus, | 2906 | 28.3k | }; | 2907 | | | 2908 | 28.3k | const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2909 | | | 2910 | 28.3k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2911 | | | 2912 | 28.3k | field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb, | 2913 | 28.3k | right[0].prime_basis_limb, | 2914 | 28.3k | quotient.prime_basis_limb * neg_prime, | 2915 | 28.3k | -remainder_prime_limb); | 2916 | | | 2917 | 28.3k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo; | 2918 | 28.3k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx); | 2919 | | | 2920 | 28.3k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2921 | 28.3k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2922 | | | 2923 | 28.3k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2924 | 0 | carry_lo_msb = 0; | 2925 | 0 | } | 2926 | 28.3k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2927 | 0 | carry_hi_msb = 0; | 2928 | 0 | } | 2929 | | | 2930 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2931 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2932 | 28.3k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2933 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2934 | 0 | lo.get_normalized_witness_index(), | 2935 | 0 | (size_t)carry_hi_msb, | 2936 | 0 | (size_t)carry_lo_msb); | 2937 | 28.3k | } else { | 2938 | 28.3k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2939 | 28.3k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2940 | 28.3k | } | 2941 | | /* NOTE TO AUDITOR: An extraneous block | 2942 | | if constexpr (HasPlookup<Builder>) { | 2943 | | carry_lo = carry_lo.normalize(); | 2944 | | carry_hi = carry_hi.normalize(); | 2945 | | ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb)); | 2946 | | ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb)); | 2947 | | } | 2948 | | was removed from the `else` block below. See the conversation at | 2949 | | https://github.com/AztecProtocol/aztec2-internal/pull/1023 | 2950 | | We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint | 2951 | | was just imposed?). */ | 2952 | 28.3k | } else { | 2953 | 28.3k | field_t b0 = left[0].binary_basis_limbs[1].element.madd( | 2954 | 28.3k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2955 | 28.3k | field_t b1 = left[0].binary_basis_limbs[0].element.madd( | 2956 | 28.3k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2957 | 28.3k | field_t c0 = left[0].binary_basis_limbs[1].element.madd( | 2958 | 28.3k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2959 | 28.3k | field_t c1 = left[0].binary_basis_limbs[2].element.madd( | 2960 | 28.3k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2961 | 28.3k | field_t c2 = left[0].binary_basis_limbs[0].element.madd( | 2962 | 28.3k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2963 | 28.3k | field_t d0 = left[0].binary_basis_limbs[3].element.madd( | 2964 | 28.3k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2965 | 28.3k | field_t d1 = left[0].binary_basis_limbs[2].element.madd( | 2966 | 28.3k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2967 | 28.3k | field_t d2 = left[0].binary_basis_limbs[1].element.madd( | 2968 | 28.3k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2969 | 28.3k | field_t d3 = left[0].binary_basis_limbs[0].element.madd( | 2970 | 28.3k | right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2971 | | | 2972 | | /** | 2973 | | * Compute "limb accumulators" | 2974 | | * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t} | 2975 | | * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS) | 2976 | | * Actual range will vary a few bits because of lazy reduction techniques | 2977 | | * | 2978 | | * We store these values in an "accumulator" vector in order to efficiently add them into a sum. | 2979 | | * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator) | 2980 | | * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single | 2981 | | * custom gate. | 2982 | | **/ | 2983 | | | 2984 | 28.3k | std::vector<field_t<Builder>> limb_0_accumulator; | 2985 | 28.3k | std::vector<field_t<Builder>> limb_2_accumulator; | 2986 | 28.3k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2987 | | | 2988 | | // Add remaining products into the limb accumulators. | 2989 | | // We negate the product values because the accumulator values itself will be negated | 2990 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 2991 | | // that the accumulators originaly tracked the remainder term (which is negated) | 2992 | | | 2993 | 28.3k | for (size_t i = 1; i < num_multiplications; ++i) { | 2994 | 28.3k | field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element; | 2995 | 28.3k | lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2); | 2996 | 28.3k | lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2); | 2997 | 28.3k | field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element; | 2998 | 28.3k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2); | 2999 | 28.3k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2); | 3000 | 28.3k | hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2); | 3001 | 28.3k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2); | 3002 | 28.3k | hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2); | 3003 | 28.3k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2); | 3004 | | | 3005 | 28.3k | limb_0_accumulator.emplace_back(-lo_2); | 3006 | 28.3k | limb_2_accumulator.emplace_back(-hi_2); | 3007 | 28.3k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 3008 | 28.3k | } | 3009 | | // add cached products into the limb accumulators. | 3010 | | // We negate the cache values because the accumulator values itself will be negated | 3011 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 3012 | | // that the accumulators originaly tracked the remainder term (which is negated) | 3013 | | | 3014 | | // Update the accumulators with the remainder terms. First check we actually have remainder terms! | 3015 | | //(not present when we're checking a product is 0 mod p). See `assert_is_in_field` | 3016 | | | 3017 | 28.3k | bool no_remainders = remainders.size() == 0; | 3018 | 28.3k | if (!no_remainders) { | 3019 | 28.3k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 3020 | 28.3k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 3021 | 28.3k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 3022 | 28.3k | } | 3023 | 28.3k | for (size_t i = 1; i < remainders.size(); ++i) { | 3024 | 28.3k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 3025 | 28.3k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 3026 | 28.3k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 3027 | 28.3k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 3028 | 28.3k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 3029 | 28.3k | } | 3030 | 28.3k | for (const auto& add : to_add) { | 3031 | 28.3k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 3032 | 28.3k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 3033 | 28.3k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 3034 | 28.3k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 3035 | 28.3k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 3036 | 28.3k | } | 3037 | | | 3038 | 28.3k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 3039 | 28.3k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 3040 | 28.3k | if (accumulated_lo.is_constant()) { | 3041 | 28.3k | accumulated_lo = | 3042 | 28.3k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 3043 | 28.3k | } | 3044 | 28.3k | if (accumulated_hi.is_constant()) { | 3045 | 28.3k | accumulated_hi = | 3046 | 28.3k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 3047 | 28.3k | } | 3048 | 28.3k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3049 | 28.3k | : remainders[0].binary_basis_limbs[1].element; | 3050 | 28.3k | if (remainder1.is_constant()) { | 3051 | 28.3k | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 3052 | 28.3k | } | 3053 | 28.3k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3054 | 28.3k | : remainders[0].binary_basis_limbs[3].element; | 3055 | 28.3k | if (remainder3.is_constant()) { | 3056 | 28.3k | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 3057 | 28.3k | } | 3058 | 28.3k | field_t<Builder> remainder_limbs[4]{ | 3059 | 28.3k | accumulated_lo, | 3060 | 28.3k | remainder1, | 3061 | 28.3k | accumulated_hi, | 3062 | 28.3k | remainder3, | 3063 | 28.3k | }; | 3064 | 28.3k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 3065 | | | 3066 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 3067 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 3068 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 3069 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 3070 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 3071 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 3072 | | | 3073 | 28.3k | field_t r0 = left[0].binary_basis_limbs[0].element.madd( | 3074 | 28.3k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3075 | 28.3k | field_t r1 = b0.add_two(b1, -remainder_limbs[1]); | 3076 | 28.3k | const field_t r2 = c0.add_two(c1, c2); | 3077 | 28.3k | const field_t r3 = d0 + d1.add_two(d2, d3); | 3078 | | | 3079 | 28.3k | field_t carry_lo_0 = r0 * shift_right_2; | 3080 | 28.3k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3081 | 28.3k | field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2); | 3082 | 28.3k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3083 | | | 3084 | 28.3k | field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1)); | 3085 | 28.3k | carry_lo += borrow_lo; | 3086 | 28.3k | field_t carry_hi_0 = r2 * shift_right_2; | 3087 | 28.3k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3088 | 28.3k | field_t carry_hi_2 = t1 * shift_right_2; | 3089 | 28.3k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3090 | | | 3091 | 28.3k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3092 | | | 3093 | 28.3k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 3094 | | | 3095 | 28.3k | linear_terms += -remainder_prime_limb; | 3096 | | | 3097 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 3098 | 28.3k | field_t<Builder>::evaluate_polynomial_identity( | 3099 | 28.3k | left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3100 | | | 3101 | 28.3k | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3102 | 28.3k | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3103 | | | 3104 | 28.3k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3105 | | | 3106 | 28.3k | if constexpr (HasPlookup<Builder>) { | 3107 | 28.3k | carry_lo = carry_lo.normalize(); | 3108 | 28.3k | carry_hi = carry_hi.normalize(); | 3109 | 28.3k | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), | 3110 | 28.3k | static_cast<size_t>(carry_lo_msb)); | 3111 | 28.3k | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), | 3112 | 28.3k | static_cast<size_t>(carry_hi_msb)); | 3113 | | | 3114 | 28.3k | } else { | 3115 | 28.3k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3116 | 28.3k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3117 | 28.3k | carry_combined = carry_combined.normalize(); | 3118 | 28.3k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3119 | 28.3k | carry_combined.get_normalized_witness_index(), | 3120 | 28.3k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3121 | 28.3k | "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add."); | 3122 | 28.3k | field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index( | 3123 | 28.3k | ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3124 | 28.3k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3125 | 28.3k | } else { | 3126 | 28.3k | carry_lo = carry_lo.normalize(); | 3127 | 28.3k | carry_hi = carry_hi.normalize(); | 3128 | 28.3k | ctx->decompose_into_base4_accumulators( | 3129 | 28.3k | carry_lo.get_normalized_witness_index(), | 3130 | 28.3k | static_cast<size_t>(carry_lo_msb), | 3131 | 28.3k | "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add."); | 3132 | 28.3k | ctx->decompose_into_base4_accumulators( | 3133 | 28.3k | carry_hi.get_normalized_witness_index(), | 3134 | 28.3k | static_cast<size_t>(carry_hi_msb), | 3135 | 28.3k | "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add."); | 3136 | 28.3k | } | 3137 | 28.3k | } | 3138 | 28.3k | } | 3139 | 28.3k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ Line | Count | Source | 2608 | 2.23k | { | 2609 | 2.23k | ASSERT(input_left.size() == input_right.size()); | 2610 | 2.23k | ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT); | 2611 | 2.23k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 2612 | 2.23k | ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT); | 2613 | | | 2614 | 2.23k | ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024); | 2615 | | // Sanity checks | 2616 | 7.01k | for (auto& el : input_left) { | 2617 | 7.01k | el.sanity_check(); | 2618 | 7.01k | } | 2619 | 7.01k | for (auto& el : input_right) { | 2620 | 7.01k | el.sanity_check(); | 2621 | 7.01k | } | 2622 | 3.19k | for (auto& el : to_add) { | 2623 | 3.19k | el.sanity_check(); | 2624 | 3.19k | } | 2625 | 2.23k | input_quotient.sanity_check(); | 2626 | 2.23k | for (auto& el : input_remainders) { | 2627 | 2.23k | el.sanity_check(); | 2628 | 2.23k | } | 2629 | 2.23k | std::vector<bigfield> remainders(input_remainders); | 2630 | 2.23k | std::vector<bigfield> left(input_left); | 2631 | 2.23k | std::vector<bigfield> right(input_right); | 2632 | 2.23k | bigfield quotient = input_quotient; | 2633 | 2.23k | const size_t num_multiplications = input_left.size(); | 2634 | | | 2635 | 2.23k | Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context; | 2636 | | | 2637 | 2.23k | const auto get_product_maximum = [](const bigfield& left, const bigfield& right) { | 2638 | 2.23k | uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2639 | 2.23k | uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2640 | 2.23k | uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2641 | 2.23k | uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2642 | 2.23k | uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2643 | 2.23k | uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value); | 2644 | 2.23k | uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value); | 2645 | 2.23k | uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value); | 2646 | 2.23k | uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value); | 2647 | 2.23k | uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value; | 2648 | | | 2649 | 2.23k | const uint512_t max_r1_inner = max_b0_inner + max_b1_inner; | 2650 | 2.23k | const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner; | 2651 | 2.23k | const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner; | 2652 | 2.23k | const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS); | 2653 | 2.23k | const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS); | 2654 | 2.23k | return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp); | 2655 | 2.23k | }; | 2656 | | | 2657 | | /** | 2658 | | * Step 1: Compute the maximum potential value of our product limbs | 2659 | | * | 2660 | | * max_lo = maximum value of limb products that span the range 0 - 2^{3t} | 2661 | | * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t} | 2662 | | * (t = NUM_LIMB_BITS) | 2663 | | **/ | 2664 | 2.23k | uint512_t max_lo = 0; | 2665 | 2.23k | uint512_t max_hi = 0; | 2666 | | | 2667 | | // Compute max values of quotient product limb products | 2668 | 2.23k | uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value); | 2669 | 2.23k | uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value); | 2670 | 2.23k | uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value); | 2671 | 2.23k | uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value); | 2672 | 2.23k | uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value); | 2673 | 2.23k | uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value); | 2674 | 2.23k | uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value); | 2675 | 2.23k | uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value); | 2676 | 2.23k | uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value); | 2677 | | | 2678 | | // max_r0 = terms from 0 - 2^2t | 2679 | | // max_r1 = terms from 2^t - 2^3t | 2680 | | // max_r2 = terms from 2^2t - 2^4t | 2681 | | // max_r3 = terms from 2^3t - 2^5t | 2682 | 2.23k | uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2683 | 2.23k | max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value); | 2684 | 2.23k | uint512_t max_r1 = max_b0 + max_b1; | 2685 | | | 2686 | 2.23k | uint256_t borrow_lo_value(0); | 2687 | 2.23k | for (const auto& remainder : input_remainders) { | 2688 | 2.23k | max_r0 += remainder.binary_basis_limbs[0].maximum_value; | 2689 | 2.23k | max_r1 += remainder.binary_basis_limbs[1].maximum_value; | 2690 | | | 2691 | 2.23k | borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value + | 2692 | 2.23k | (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2693 | 2.23k | } | 2694 | 2.23k | borrow_lo_value >>= 2 * NUM_LIMB_BITS; | 2695 | 2.23k | field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value)); | 2696 | | | 2697 | 2.23k | const uint512_t max_r2 = max_c0 + max_c1 + max_c2; | 2698 | 2.23k | const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3; | 2699 | | | 2700 | | // update max_lo, max_hi with quotient limb product terms. | 2701 | 2.23k | max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS); | 2702 | 2.23k | max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS); | 2703 | | | 2704 | | // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi | 2705 | 2.23k | uint512_t max_a0(0); | 2706 | 2.23k | uint512_t max_a1(0); | 2707 | 5.42k | for (size_t i = 0; i < to_add.size(); ++i) { | 2708 | 3.19k | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 2709 | 3.19k | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 2710 | 3.19k | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 2711 | 3.19k | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 2712 | 3.19k | } | 2713 | 2.23k | max_lo += max_a0; | 2714 | 2.23k | max_hi += max_a1; | 2715 | | | 2716 | | // Compute the maximum value of our multiplication products and add to max_lo, max_hi | 2717 | 9.24k | for (size_t i = 0; i < num_multiplications; ++i) { | 2718 | 7.01k | const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]); | 2719 | 7.01k | max_lo += product_lo; | 2720 | 7.01k | max_hi += product_hi; | 2721 | 7.01k | } | 2722 | | | 2723 | 2.23k | const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS); | 2724 | 2.23k | max_hi += max_lo_carry; | 2725 | | // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we | 2726 | | // will need to apply to validate our product | 2727 | 2.23k | uint64_t max_lo_bits = (max_lo.get_msb() + 1); | 2728 | 2.23k | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 2729 | | // Turbo range checks only work for even bit ranges, so make sure these values are even | 2730 | | // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges... | 2731 | 2.23k | if ((max_lo_bits & 1ULL) == 1ULL) { | 2732 | 1.59k | ++max_lo_bits; | 2733 | 1.59k | } | 2734 | 2.23k | if ((max_hi_bits & 1ULL) == 1ULL) { | 2735 | 1.59k | ++max_hi_bits; | 2736 | 1.59k | } | 2737 | | | 2738 | 2.23k | if constexpr (HasPlookup<Builder>) { | 2739 | | // The plookup custom bigfield gate requires inputs are witnesses. | 2740 | | // If we're using constant values, instantiate them as circuit variables | 2741 | | | 2742 | 2.23k | const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) { | 2743 | 2.23k | bigfield output(input); | 2744 | 2.23k | output.prime_basis_limb = field_t<Builder>::from_witness_index( | 2745 | 2.23k | ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value())); | 2746 | 2.23k | output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index( | 2747 | 2.23k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value())); | 2748 | 2.23k | output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index( | 2749 | 2.23k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value())); | 2750 | 2.23k | output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index( | 2751 | 2.23k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value())); | 2752 | 2.23k | output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index( | 2753 | 2.23k | ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value())); | 2754 | 2.23k | output.context = ctx; | 2755 | 2.23k | return output; | 2756 | 2.23k | }; | 2757 | | | 2758 | | // evalaute a nnf mul and add into existing lohi output for our extra product terms | 2759 | | // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx | 2760 | | // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136} | 2761 | | // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values | 2762 | | // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication + | 2763 | | // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If | 2764 | | // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into | 2765 | | // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting | 2766 | | // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two | 2767 | | // calls to `evaluate_non_native_field_multiplication` | 2768 | 2.23k | std::vector<field_t<Builder>> limb_0_accumulator; | 2769 | 2.23k | std::vector<field_t<Builder>> limb_2_accumulator; | 2770 | 2.23k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2771 | | | 2772 | 9.24k | for (size_t i = 0; i < num_multiplications; ++i) { | 2773 | 7.01k | if (i == 0 && left[0].is_constant()) { | 2774 | 0 | left[0] = convert_constant_to_fixed_witness(left[0]); | 2775 | 0 | } | 2776 | 7.01k | if (i == 0 && right[0].is_constant()) { | 2777 | 0 | right[0] = convert_constant_to_fixed_witness(right[0]); | 2778 | 0 | } | 2779 | 7.01k | if (i > 0 && left[i].is_constant()) { | 2780 | 0 | left[i] = convert_constant_to_fixed_witness(left[i]); | 2781 | 0 | } | 2782 | 7.01k | if (i > 0 && right[i].is_constant()) { | 2783 | 4 | right[i] = convert_constant_to_fixed_witness(right[i]); | 2784 | 4 | } | 2785 | | | 2786 | 7.01k | if (i > 0) { | 2787 | 4.77k | bb::non_native_field_witnesses<bb::fr> mul_witnesses = { | 2788 | 4.77k | { | 2789 | 4.77k | left[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2790 | 4.77k | left[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2791 | 4.77k | left[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2792 | 4.77k | left[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2793 | 4.77k | }, | 2794 | 4.77k | { | 2795 | 4.77k | right[i].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2796 | 4.77k | right[i].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2797 | 4.77k | right[i].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2798 | 4.77k | right[i].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2799 | 4.77k | }, | 2800 | 4.77k | { | 2801 | 4.77k | ctx->zero_idx, | 2802 | 4.77k | ctx->zero_idx, | 2803 | 4.77k | ctx->zero_idx, | 2804 | 4.77k | ctx->zero_idx, | 2805 | 4.77k | }, | 2806 | 4.77k | { | 2807 | 4.77k | ctx->zero_idx, | 2808 | 4.77k | ctx->zero_idx, | 2809 | 4.77k | ctx->zero_idx, | 2810 | 4.77k | ctx->zero_idx, | 2811 | 4.77k | }, | 2812 | 4.77k | { 0, 0, 0, 0 }, | 2813 | 4.77k | modulus, | 2814 | 4.77k | }; | 2815 | | | 2816 | 4.77k | const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses); | 2817 | | | 2818 | 4.77k | field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx); | 2819 | 4.77k | field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx); | 2820 | | | 2821 | 4.77k | limb_0_accumulator.emplace_back(-lo_2); | 2822 | 4.77k | limb_2_accumulator.emplace_back(-hi_2); | 2823 | 4.77k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 2824 | 4.77k | } | 2825 | 7.01k | } | 2826 | 2.23k | if (quotient.is_constant()) { | 2827 | 0 | quotient = convert_constant_to_fixed_witness(quotient); | 2828 | 0 | } | 2829 | | | 2830 | 2.23k | bool no_remainders = remainders.size() == 0; | 2831 | 2.23k | if (!no_remainders) { | 2832 | 2.23k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 2833 | 2.23k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 2834 | 2.23k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 2835 | 2.23k | } | 2836 | 2.23k | for (size_t i = 1; i < remainders.size(); ++i) { | 2837 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 2838 | 0 | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 2839 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 2840 | 0 | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 2841 | 0 | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 2842 | 0 | } | 2843 | 3.19k | for (const auto& add : to_add) { | 2844 | 3.19k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 2845 | 3.19k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 2846 | 3.19k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 2847 | 3.19k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 2848 | 3.19k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 2849 | 3.19k | } | 2850 | | | 2851 | 2.23k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 2852 | 2.23k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 2853 | 2.23k | if (accumulated_lo.is_constant()) { | 2854 | 0 | accumulated_lo = | 2855 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 2856 | 0 | } | 2857 | 2.23k | if (accumulated_hi.is_constant()) { | 2858 | 0 | accumulated_hi = | 2859 | 0 | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 2860 | 0 | } | 2861 | 2.23k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2862 | 2.23k | : remainders[0].binary_basis_limbs[1].element; | 2863 | 2.23k | if (remainder1.is_constant()) { | 2864 | 0 | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 2865 | 0 | } | 2866 | 2.23k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 2867 | 2.23k | : remainders[0].binary_basis_limbs[3].element; | 2868 | 2.23k | if (remainder3.is_constant()) { | 2869 | 0 | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 2870 | 0 | } | 2871 | 2.23k | field_t<Builder> remainder_limbs[4]{ | 2872 | 2.23k | accumulated_lo, | 2873 | 2.23k | remainder1, | 2874 | 2.23k | accumulated_hi, | 2875 | 2.23k | remainder3, | 2876 | 2.23k | }; | 2877 | 2.23k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 2878 | | | 2879 | 2.23k | bb::non_native_field_witnesses<bb::fr> witnesses{ | 2880 | 2.23k | { | 2881 | 2.23k | left[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2882 | 2.23k | left[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2883 | 2.23k | left[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2884 | 2.23k | left[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2885 | 2.23k | }, | 2886 | 2.23k | { | 2887 | 2.23k | right[0].binary_basis_limbs[0].element.get_normalized_witness_index(), | 2888 | 2.23k | right[0].binary_basis_limbs[1].element.get_normalized_witness_index(), | 2889 | 2.23k | right[0].binary_basis_limbs[2].element.get_normalized_witness_index(), | 2890 | 2.23k | right[0].binary_basis_limbs[3].element.get_normalized_witness_index(), | 2891 | 2.23k | }, | 2892 | 2.23k | { | 2893 | 2.23k | quotient.binary_basis_limbs[0].element.get_normalized_witness_index(), | 2894 | 2.23k | quotient.binary_basis_limbs[1].element.get_normalized_witness_index(), | 2895 | 2.23k | quotient.binary_basis_limbs[2].element.get_normalized_witness_index(), | 2896 | 2.23k | quotient.binary_basis_limbs[3].element.get_normalized_witness_index(), | 2897 | 2.23k | }, | 2898 | 2.23k | { | 2899 | 2.23k | remainder_limbs[0].get_normalized_witness_index(), | 2900 | 2.23k | remainder_limbs[1].get_normalized_witness_index(), | 2901 | 2.23k | remainder_limbs[2].get_normalized_witness_index(), | 2902 | 2.23k | remainder_limbs[3].get_normalized_witness_index(), | 2903 | 2.23k | }, | 2904 | 2.23k | { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] }, | 2905 | 2.23k | modulus, | 2906 | 2.23k | }; | 2907 | | | 2908 | 2.23k | const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses); | 2909 | | | 2910 | 2.23k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 2911 | | | 2912 | 2.23k | field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb, | 2913 | 2.23k | right[0].prime_basis_limb, | 2914 | 2.23k | quotient.prime_basis_limb * neg_prime, | 2915 | 2.23k | -remainder_prime_limb); | 2916 | | | 2917 | 2.23k | field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo; | 2918 | 2.23k | field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx); | 2919 | | | 2920 | 2.23k | uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 2921 | 2.23k | uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 2922 | | | 2923 | 2.23k | if (max_lo_bits < (2 * NUM_LIMB_BITS)) { | 2924 | 0 | carry_lo_msb = 0; | 2925 | 0 | } | 2926 | 2.23k | if (max_hi_bits < (2 * NUM_LIMB_BITS)) { | 2927 | 0 | carry_hi_msb = 0; | 2928 | 0 | } | 2929 | | | 2930 | | // if both the hi and lo output limbs have less than 70 bits, we can use our custom | 2931 | | // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) | 2932 | 2.23k | if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { | 2933 | 0 | ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(), | 2934 | 0 | lo.get_normalized_witness_index(), | 2935 | 0 | (size_t)carry_hi_msb, | 2936 | 0 | (size_t)carry_lo_msb); | 2937 | 2.23k | } else { | 2938 | 2.23k | ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb); | 2939 | 2.23k | ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb); | 2940 | 2.23k | } | 2941 | | /* NOTE TO AUDITOR: An extraneous block | 2942 | | if constexpr (HasPlookup<Builder>) { | 2943 | | carry_lo = carry_lo.normalize(); | 2944 | | carry_hi = carry_hi.normalize(); | 2945 | | ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb)); | 2946 | | ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb)); | 2947 | | } | 2948 | | was removed from the `else` block below. See the conversation at | 2949 | | https://github.com/AztecProtocol/aztec2-internal/pull/1023 | 2950 | | We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint | 2951 | | was just imposed?). */ | 2952 | 2.23k | } else { | 2953 | 2.23k | field_t b0 = left[0].binary_basis_limbs[1].element.madd( | 2954 | 2.23k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 2955 | 2.23k | field_t b1 = left[0].binary_basis_limbs[0].element.madd( | 2956 | 2.23k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 2957 | 2.23k | field_t c0 = left[0].binary_basis_limbs[1].element.madd( | 2958 | 2.23k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 2959 | 2.23k | field_t c1 = left[0].binary_basis_limbs[2].element.madd( | 2960 | 2.23k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 2961 | 2.23k | field_t c2 = left[0].binary_basis_limbs[0].element.madd( | 2962 | 2.23k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 2963 | 2.23k | field_t d0 = left[0].binary_basis_limbs[3].element.madd( | 2964 | 2.23k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 2965 | 2.23k | field_t d1 = left[0].binary_basis_limbs[2].element.madd( | 2966 | 2.23k | right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 2967 | 2.23k | field_t d2 = left[0].binary_basis_limbs[1].element.madd( | 2968 | 2.23k | right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 2969 | 2.23k | field_t d3 = left[0].binary_basis_limbs[0].element.madd( | 2970 | 2.23k | right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 2971 | | | 2972 | | /** | 2973 | | * Compute "limb accumulators" | 2974 | | * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t} | 2975 | | * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS) | 2976 | | * Actual range will vary a few bits because of lazy reduction techniques | 2977 | | * | 2978 | | * We store these values in an "accumulator" vector in order to efficiently add them into a sum. | 2979 | | * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator) | 2980 | | * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single | 2981 | | * custom gate. | 2982 | | **/ | 2983 | | | 2984 | 2.23k | std::vector<field_t<Builder>> limb_0_accumulator; | 2985 | 2.23k | std::vector<field_t<Builder>> limb_2_accumulator; | 2986 | 2.23k | std::vector<field_t<Builder>> prime_limb_accumulator; | 2987 | | | 2988 | | // Add remaining products into the limb accumulators. | 2989 | | // We negate the product values because the accumulator values itself will be negated | 2990 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 2991 | | // that the accumulators originaly tracked the remainder term (which is negated) | 2992 | | | 2993 | 2.23k | for (size_t i = 1; i < num_multiplications; ++i) { | 2994 | 2.23k | field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element; | 2995 | 2.23k | lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2); | 2996 | 2.23k | lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2); | 2997 | 2.23k | field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element; | 2998 | 2.23k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2); | 2999 | 2.23k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2); | 3000 | 2.23k | hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2); | 3001 | 2.23k | hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2); | 3002 | 2.23k | hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2); | 3003 | 2.23k | hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2); | 3004 | | | 3005 | 2.23k | limb_0_accumulator.emplace_back(-lo_2); | 3006 | 2.23k | limb_2_accumulator.emplace_back(-hi_2); | 3007 | 2.23k | prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb)); | 3008 | 2.23k | } | 3009 | | // add cached products into the limb accumulators. | 3010 | | // We negate the cache values because the accumulator values itself will be negated | 3011 | | // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact | 3012 | | // that the accumulators originaly tracked the remainder term (which is negated) | 3013 | | | 3014 | | // Update the accumulators with the remainder terms. First check we actually have remainder terms! | 3015 | | //(not present when we're checking a product is 0 mod p). See `assert_is_in_field` | 3016 | | | 3017 | 2.23k | bool no_remainders = remainders.size() == 0; | 3018 | 2.23k | if (!no_remainders) { | 3019 | 2.23k | limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element); | 3020 | 2.23k | limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element); | 3021 | 2.23k | prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb); | 3022 | 2.23k | } | 3023 | 2.23k | for (size_t i = 1; i < remainders.size(); ++i) { | 3024 | 2.23k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element); | 3025 | 2.23k | limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1); | 3026 | 2.23k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element); | 3027 | 2.23k | limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1); | 3028 | 2.23k | prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb); | 3029 | 2.23k | } | 3030 | 2.23k | for (const auto& add : to_add) { | 3031 | 2.23k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element); | 3032 | 2.23k | limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1); | 3033 | 2.23k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element); | 3034 | 2.23k | limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1); | 3035 | 2.23k | prime_limb_accumulator.emplace_back(-add.prime_basis_limb); | 3036 | 2.23k | } | 3037 | | | 3038 | 2.23k | field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator); | 3039 | 2.23k | field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator); | 3040 | 2.23k | if (accumulated_lo.is_constant()) { | 3041 | 2.23k | accumulated_lo = | 3042 | 2.23k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value())); | 3043 | 2.23k | } | 3044 | 2.23k | if (accumulated_hi.is_constant()) { | 3045 | 2.23k | accumulated_hi = | 3046 | 2.23k | field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value())); | 3047 | 2.23k | } | 3048 | 2.23k | field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3049 | 2.23k | : remainders[0].binary_basis_limbs[1].element; | 3050 | 2.23k | if (remainder1.is_constant()) { | 3051 | 2.23k | remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value())); | 3052 | 2.23k | } | 3053 | 2.23k | field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx) | 3054 | 2.23k | : remainders[0].binary_basis_limbs[3].element; | 3055 | 2.23k | if (remainder3.is_constant()) { | 3056 | 2.23k | remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value())); | 3057 | 2.23k | } | 3058 | 2.23k | field_t<Builder> remainder_limbs[4]{ | 3059 | 2.23k | accumulated_lo, | 3060 | 2.23k | remainder1, | 3061 | 2.23k | accumulated_hi, | 3062 | 2.23k | remainder3, | 3063 | 2.23k | }; | 3064 | 2.23k | field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator); | 3065 | | | 3066 | | // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb | 3067 | | // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap | 3068 | | // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion | 3069 | | // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning | 3070 | | // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are | 3071 | | // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2} | 3072 | | | 3073 | 2.23k | field_t r0 = left[0].binary_basis_limbs[0].element.madd( | 3074 | 2.23k | right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3075 | 2.23k | field_t r1 = b0.add_two(b1, -remainder_limbs[1]); | 3076 | 2.23k | const field_t r2 = c0.add_two(c1, c2); | 3077 | 2.23k | const field_t r3 = d0 + d1.add_two(d2, d3); | 3078 | | | 3079 | 2.23k | field_t carry_lo_0 = r0 * shift_right_2; | 3080 | 2.23k | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3081 | 2.23k | field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2); | 3082 | 2.23k | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3083 | | | 3084 | 2.23k | field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1)); | 3085 | 2.23k | carry_lo += borrow_lo; | 3086 | 2.23k | field_t carry_hi_0 = r2 * shift_right_2; | 3087 | 2.23k | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3088 | 2.23k | field_t carry_hi_2 = t1 * shift_right_2; | 3089 | 2.23k | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3090 | | | 3091 | 2.23k | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3092 | | | 3093 | 2.23k | field_t<Builder> linear_terms(ctx, bb::fr(0)); | 3094 | | | 3095 | 2.23k | linear_terms += -remainder_prime_limb; | 3096 | | | 3097 | | // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t) | 3098 | 2.23k | field_t<Builder>::evaluate_polynomial_identity( | 3099 | 2.23k | left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3100 | | | 3101 | 2.23k | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3102 | 2.23k | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3103 | | | 3104 | 2.23k | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3105 | | | 3106 | 2.23k | if constexpr (HasPlookup<Builder>) { | 3107 | 2.23k | carry_lo = carry_lo.normalize(); | 3108 | 2.23k | carry_hi = carry_hi.normalize(); | 3109 | 2.23k | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), | 3110 | 2.23k | static_cast<size_t>(carry_lo_msb)); | 3111 | 2.23k | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), | 3112 | 2.23k | static_cast<size_t>(carry_hi_msb)); | 3113 | | | 3114 | 2.23k | } else { | 3115 | 2.23k | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3116 | 2.23k | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3117 | 2.23k | carry_combined = carry_combined.normalize(); | 3118 | 2.23k | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3119 | 2.23k | carry_combined.get_normalized_witness_index(), | 3120 | 2.23k | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3121 | 2.23k | "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add."); | 3122 | 2.23k | field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index( | 3123 | 2.23k | ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3124 | 2.23k | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3125 | 2.23k | } else { | 3126 | 2.23k | carry_lo = carry_lo.normalize(); | 3127 | 2.23k | carry_hi = carry_hi.normalize(); | 3128 | 2.23k | ctx->decompose_into_base4_accumulators( | 3129 | 2.23k | carry_lo.get_normalized_witness_index(), | 3130 | 2.23k | static_cast<size_t>(carry_lo_msb), | 3131 | 2.23k | "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add."); | 3132 | 2.23k | ctx->decompose_into_base4_accumulators( | 3133 | 2.23k | carry_hi.get_normalized_witness_index(), | 3134 | 2.23k | static_cast<size_t>(carry_hi_msb), | 3135 | 2.23k | "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add."); | 3136 | 2.23k | } | 3137 | 2.23k | } | 3138 | 2.23k | } | 3139 | 2.23k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ |
3140 | | |
3141 | | template <typename Builder, typename T> |
3142 | | void bigfield<Builder, T>::unsafe_evaluate_square_add(const bigfield& left, |
3143 | | const std::vector<bigfield>& to_add, |
3144 | | const bigfield& quotient, |
3145 | | const bigfield& remainder) |
3146 | 381k | { |
3147 | 381k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
3148 | | |
3149 | 381k | if (HasPlookup<Builder>) { |
3150 | 381k | unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder }); |
3151 | 381k | return; |
3152 | 381k | } |
3153 | | |
3154 | | // Sanity checks |
3155 | 0 | left.sanity_check(); |
3156 | 0 | remainder.sanity_check(); |
3157 | 0 | quotient.sanity_check(); |
3158 | 0 | for (auto& el : to_add) { |
3159 | 0 | el.sanity_check(); |
3160 | 0 | } |
3161 | |
|
3162 | 0 | Builder* ctx = left.context == nullptr ? quotient.context : left.context; |
3163 | |
|
3164 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value); |
3165 | 0 | max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); |
3166 | 0 | max_b0 += max_b0; |
3167 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value); |
3168 | 0 | max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); |
3169 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value); |
3170 | 0 | max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); |
3171 | 0 | max_c1 += max_c1; |
3172 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value); |
3173 | 0 | max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS); |
3174 | 0 | max_d0 += max_d0; |
3175 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value); |
3176 | 0 | max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); |
3177 | 0 | max_d1 += max_d1; |
3178 | |
|
3179 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value; |
3180 | 0 | max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS); |
3181 | |
|
3182 | 0 | const uint512_t max_r1 = max_b0; |
3183 | 0 | const uint512_t max_r2 = max_c0 + max_c1; |
3184 | 0 | const uint512_t max_r3 = max_d0 + max_d1; |
3185 | |
|
3186 | 0 | uint512_t max_a0(0); |
3187 | 0 | uint512_t max_a1(1); |
3188 | 0 | for (size_t i = 0; i < to_add.size(); ++i) { |
3189 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + |
3190 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); |
3191 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + |
3192 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); |
3193 | 0 | } |
3194 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; |
3195 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1; |
3196 | |
|
3197 | 0 | uint64_t max_lo_bits = max_lo.get_msb() + 1; |
3198 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; |
3199 | 0 | if ((max_lo_bits & 1ULL) == 1ULL) { |
3200 | 0 | ++max_lo_bits; |
3201 | 0 | } |
3202 | 0 | if ((max_hi_bits & 1ULL) == 1ULL) { |
3203 | 0 | ++max_hi_bits; |
3204 | 0 | } |
3205 | |
|
3206 | 0 | field_t half(ctx, bb::fr(2).invert()); |
3207 | 0 | field_t two(ctx, bb::fr(2)); |
3208 | 0 | field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); |
3209 | 0 | field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); |
3210 | |
|
3211 | 0 | field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); |
3212 | 0 | field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); |
3213 | |
|
3214 | 0 | field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); |
3215 | 0 | field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); |
3216 | 0 | field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); |
3217 | 0 | field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); |
3218 | |
|
3219 | 0 | const field_t b0 = |
3220 | 0 | two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half); |
3221 | |
|
3222 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( |
3223 | 0 | left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); |
3224 | 0 | const field_t c1 = |
3225 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half); |
3226 | |
|
3227 | 0 | const field_t d0 = |
3228 | 0 | two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half); |
3229 | |
|
3230 | 0 | const field_t d1 = |
3231 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half); |
3232 | |
|
3233 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( |
3234 | 0 | left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); |
3235 | |
|
3236 | 0 | const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element); |
3237 | 0 | const field_t r2 = c0.add_two(c_quotient_1, c1); |
3238 | 0 | const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3; |
3239 | |
|
3240 | 0 | field_t carry_lo_0 = r0 * shift_right_2; |
3241 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); |
3242 | 0 | field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2); |
3243 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); |
3244 | |
|
3245 | 0 | for (const auto& add_element : to_add) { |
3246 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, |
3247 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); |
3248 | 0 | } |
3249 | |
|
3250 | 0 | field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element, |
3251 | 0 | -(remainder.binary_basis_limbs[3].element * shift_1)); |
3252 | 0 | field_t carry_hi_0 = r2 * shift_right_2; |
3253 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); |
3254 | 0 | field_t carry_hi_2 = t1 * shift_right_2; |
3255 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); |
3256 | |
|
3257 | 0 | for (const auto& add_element : to_add) { |
3258 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, |
3259 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); |
3260 | 0 | } |
3261 | |
|
3262 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); |
3263 | 0 | field_t<Builder> linear_terms = -remainder.prime_basis_limb; |
3264 | 0 | if (to_add.size() >= 2) { |
3265 | 0 | for (size_t i = 0; i < to_add.size() / 2; i += 1) { |
3266 | 0 | linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb); |
3267 | 0 | } |
3268 | 0 | } |
3269 | 0 | if ((to_add.size() & 1UL) == 1UL) { |
3270 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; |
3271 | 0 | } |
3272 | 0 | field_t<Builder>::evaluate_polynomial_identity( |
3273 | 0 | left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); |
3274 | |
|
3275 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); |
3276 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); |
3277 | |
|
3278 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); |
3279 | 0 | if constexpr (HasPlookup<Builder>) { |
3280 | 0 | carry_lo = carry_lo.normalize(); |
3281 | 0 | carry_hi = carry_hi.normalize(); |
3282 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb)); |
3283 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb)); |
3284 | |
|
3285 | 0 | } else { |
3286 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { |
3287 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); |
3288 | 0 | carry_combined = carry_combined.normalize(); |
3289 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( |
3290 | 0 | carry_combined.get_normalized_witness_index(), |
3291 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), |
3292 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_square_add."); |
3293 | 0 | field_t<Builder> accumulator_midpoint = |
3294 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); |
3295 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); |
3296 | 0 | } else { |
3297 | 0 | carry_lo = carry_lo.normalize(); |
3298 | 0 | carry_hi = carry_hi.normalize(); |
3299 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), |
3300 | 0 | static_cast<size_t>(carry_lo_msb), |
3301 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_square_add."); |
3302 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), |
3303 | 0 | static_cast<size_t>(carry_hi_msb), |
3304 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_square_add"); |
3305 | 0 | } |
3306 | 0 | } |
3307 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_ Line | Count | Source | 3146 | 357k | { | 3147 | 357k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3148 | | | 3149 | 357k | if (HasPlookup<Builder>) { | 3150 | 357k | unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder }); | 3151 | 357k | return; | 3152 | 357k | } | 3153 | | | 3154 | | // Sanity checks | 3155 | 0 | left.sanity_check(); | 3156 | 0 | remainder.sanity_check(); | 3157 | 0 | quotient.sanity_check(); | 3158 | 0 | for (auto& el : to_add) { | 3159 | 0 | el.sanity_check(); | 3160 | 0 | } | 3161 | |
| 3162 | 0 | Builder* ctx = left.context == nullptr ? quotient.context : left.context; | 3163 | |
| 3164 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3165 | 0 | max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3166 | 0 | max_b0 += max_b0; | 3167 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3168 | 0 | max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3169 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3170 | 0 | max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3171 | 0 | max_c1 += max_c1; | 3172 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3173 | 0 | max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS); | 3174 | 0 | max_d0 += max_d0; | 3175 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3176 | 0 | max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3177 | 0 | max_d1 += max_d1; | 3178 | |
| 3179 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value; | 3180 | 0 | max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS); | 3181 | |
| 3182 | 0 | const uint512_t max_r1 = max_b0; | 3183 | 0 | const uint512_t max_r2 = max_c0 + max_c1; | 3184 | 0 | const uint512_t max_r3 = max_d0 + max_d1; | 3185 | |
| 3186 | 0 | uint512_t max_a0(0); | 3187 | 0 | uint512_t max_a1(1); | 3188 | 0 | for (size_t i = 0; i < to_add.size(); ++i) { | 3189 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 3190 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 3191 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 3192 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 3193 | 0 | } | 3194 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 3195 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1; | 3196 | |
| 3197 | 0 | uint64_t max_lo_bits = max_lo.get_msb() + 1; | 3198 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 3199 | 0 | if ((max_lo_bits & 1ULL) == 1ULL) { | 3200 | 0 | ++max_lo_bits; | 3201 | 0 | } | 3202 | 0 | if ((max_hi_bits & 1ULL) == 1ULL) { | 3203 | 0 | ++max_hi_bits; | 3204 | 0 | } | 3205 | |
| 3206 | 0 | field_t half(ctx, bb::fr(2).invert()); | 3207 | 0 | field_t two(ctx, bb::fr(2)); | 3208 | 0 | field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 3209 | 0 | field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 3210 | |
| 3211 | 0 | field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 3212 | 0 | field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 3213 | |
| 3214 | 0 | field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 3215 | 0 | field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 3216 | 0 | field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 3217 | 0 | field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 3218 | |
| 3219 | 0 | const field_t b0 = | 3220 | 0 | two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half); | 3221 | |
| 3222 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 3223 | 0 | left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 3224 | 0 | const field_t c1 = | 3225 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half); | 3226 | |
| 3227 | 0 | const field_t d0 = | 3228 | 0 | two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half); | 3229 | |
| 3230 | 0 | const field_t d1 = | 3231 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half); | 3232 | |
| 3233 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 3234 | 0 | left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3235 | |
| 3236 | 0 | const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element); | 3237 | 0 | const field_t r2 = c0.add_two(c_quotient_1, c1); | 3238 | 0 | const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3; | 3239 | |
| 3240 | 0 | field_t carry_lo_0 = r0 * shift_right_2; | 3241 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3242 | 0 | field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2); | 3243 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3244 | |
| 3245 | 0 | for (const auto& add_element : to_add) { | 3246 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 3247 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 3248 | 0 | } | 3249 | |
| 3250 | 0 | field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element, | 3251 | 0 | -(remainder.binary_basis_limbs[3].element * shift_1)); | 3252 | 0 | field_t carry_hi_0 = r2 * shift_right_2; | 3253 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3254 | 0 | field_t carry_hi_2 = t1 * shift_right_2; | 3255 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3256 | |
| 3257 | 0 | for (const auto& add_element : to_add) { | 3258 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 3259 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 3260 | 0 | } | 3261 | |
| 3262 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3263 | 0 | field_t<Builder> linear_terms = -remainder.prime_basis_limb; | 3264 | 0 | if (to_add.size() >= 2) { | 3265 | 0 | for (size_t i = 0; i < to_add.size() / 2; i += 1) { | 3266 | 0 | linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb); | 3267 | 0 | } | 3268 | 0 | } | 3269 | 0 | if ((to_add.size() & 1UL) == 1UL) { | 3270 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 3271 | 0 | } | 3272 | 0 | field_t<Builder>::evaluate_polynomial_identity( | 3273 | 0 | left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3274 | |
| 3275 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3276 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3277 | |
| 3278 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3279 | 0 | if constexpr (HasPlookup<Builder>) { | 3280 | 0 | carry_lo = carry_lo.normalize(); | 3281 | 0 | carry_hi = carry_hi.normalize(); | 3282 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb)); | 3283 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb)); | 3284 | |
| 3285 | 0 | } else { | 3286 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3287 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3288 | 0 | carry_combined = carry_combined.normalize(); | 3289 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3290 | 0 | carry_combined.get_normalized_witness_index(), | 3291 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3292 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_square_add."); | 3293 | 0 | field_t<Builder> accumulator_midpoint = | 3294 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3295 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3296 | 0 | } else { | 3297 | 0 | carry_lo = carry_lo.normalize(); | 3298 | 0 | carry_hi = carry_hi.normalize(); | 3299 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 3300 | 0 | static_cast<size_t>(carry_lo_msb), | 3301 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_square_add."); | 3302 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 3303 | 0 | static_cast<size_t>(carry_hi_msb), | 3304 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_square_add"); | 3305 | 0 | } | 3306 | 0 | } | 3307 | 0 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ Line | Count | Source | 3146 | 1.01k | { | 3147 | 1.01k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3148 | | | 3149 | 1.01k | if (HasPlookup<Builder>) { | 3150 | 1.01k | unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder }); | 3151 | 1.01k | return; | 3152 | 1.01k | } | 3153 | | | 3154 | | // Sanity checks | 3155 | 0 | left.sanity_check(); | 3156 | 0 | remainder.sanity_check(); | 3157 | 0 | quotient.sanity_check(); | 3158 | 0 | for (auto& el : to_add) { | 3159 | 0 | el.sanity_check(); | 3160 | 0 | } | 3161 | |
| 3162 | 0 | Builder* ctx = left.context == nullptr ? quotient.context : left.context; | 3163 | |
| 3164 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3165 | 0 | max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3166 | 0 | max_b0 += max_b0; | 3167 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3168 | 0 | max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3169 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3170 | 0 | max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3171 | 0 | max_c1 += max_c1; | 3172 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3173 | 0 | max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS); | 3174 | 0 | max_d0 += max_d0; | 3175 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3176 | 0 | max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3177 | 0 | max_d1 += max_d1; | 3178 | |
| 3179 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value; | 3180 | 0 | max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS); | 3181 | |
| 3182 | 0 | const uint512_t max_r1 = max_b0; | 3183 | 0 | const uint512_t max_r2 = max_c0 + max_c1; | 3184 | 0 | const uint512_t max_r3 = max_d0 + max_d1; | 3185 | |
| 3186 | 0 | uint512_t max_a0(0); | 3187 | 0 | uint512_t max_a1(1); | 3188 | 0 | for (size_t i = 0; i < to_add.size(); ++i) { | 3189 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 3190 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 3191 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 3192 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 3193 | 0 | } | 3194 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 3195 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1; | 3196 | |
| 3197 | 0 | uint64_t max_lo_bits = max_lo.get_msb() + 1; | 3198 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 3199 | 0 | if ((max_lo_bits & 1ULL) == 1ULL) { | 3200 | 0 | ++max_lo_bits; | 3201 | 0 | } | 3202 | 0 | if ((max_hi_bits & 1ULL) == 1ULL) { | 3203 | 0 | ++max_hi_bits; | 3204 | 0 | } | 3205 | |
| 3206 | 0 | field_t half(ctx, bb::fr(2).invert()); | 3207 | 0 | field_t two(ctx, bb::fr(2)); | 3208 | 0 | field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 3209 | 0 | field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 3210 | |
| 3211 | 0 | field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 3212 | 0 | field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 3213 | |
| 3214 | 0 | field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 3215 | 0 | field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 3216 | 0 | field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 3217 | 0 | field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 3218 | |
| 3219 | 0 | const field_t b0 = | 3220 | 0 | two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half); | 3221 | |
| 3222 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 3223 | 0 | left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 3224 | 0 | const field_t c1 = | 3225 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half); | 3226 | |
| 3227 | 0 | const field_t d0 = | 3228 | 0 | two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half); | 3229 | |
| 3230 | 0 | const field_t d1 = | 3231 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half); | 3232 | |
| 3233 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 3234 | 0 | left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3235 | |
| 3236 | 0 | const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element); | 3237 | 0 | const field_t r2 = c0.add_two(c_quotient_1, c1); | 3238 | 0 | const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3; | 3239 | |
| 3240 | 0 | field_t carry_lo_0 = r0 * shift_right_2; | 3241 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3242 | 0 | field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2); | 3243 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3244 | |
| 3245 | 0 | for (const auto& add_element : to_add) { | 3246 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 3247 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 3248 | 0 | } | 3249 | |
| 3250 | 0 | field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element, | 3251 | 0 | -(remainder.binary_basis_limbs[3].element * shift_1)); | 3252 | 0 | field_t carry_hi_0 = r2 * shift_right_2; | 3253 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3254 | 0 | field_t carry_hi_2 = t1 * shift_right_2; | 3255 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3256 | |
| 3257 | 0 | for (const auto& add_element : to_add) { | 3258 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 3259 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 3260 | 0 | } | 3261 | |
| 3262 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3263 | 0 | field_t<Builder> linear_terms = -remainder.prime_basis_limb; | 3264 | 0 | if (to_add.size() >= 2) { | 3265 | 0 | for (size_t i = 0; i < to_add.size() / 2; i += 1) { | 3266 | 0 | linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb); | 3267 | 0 | } | 3268 | 0 | } | 3269 | 0 | if ((to_add.size() & 1UL) == 1UL) { | 3270 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 3271 | 0 | } | 3272 | 0 | field_t<Builder>::evaluate_polynomial_identity( | 3273 | 0 | left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3274 | |
| 3275 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3276 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3277 | |
| 3278 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3279 | 0 | if constexpr (HasPlookup<Builder>) { | 3280 | 0 | carry_lo = carry_lo.normalize(); | 3281 | 0 | carry_hi = carry_hi.normalize(); | 3282 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb)); | 3283 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb)); | 3284 | |
| 3285 | 0 | } else { | 3286 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3287 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3288 | 0 | carry_combined = carry_combined.normalize(); | 3289 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3290 | 0 | carry_combined.get_normalized_witness_index(), | 3291 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3292 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_square_add."); | 3293 | 0 | field_t<Builder> accumulator_midpoint = | 3294 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3295 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3296 | 0 | } else { | 3297 | 0 | carry_lo = carry_lo.normalize(); | 3298 | 0 | carry_hi = carry_hi.normalize(); | 3299 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 3300 | 0 | static_cast<size_t>(carry_lo_msb), | 3301 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_square_add."); | 3302 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 3303 | 0 | static_cast<size_t>(carry_hi_msb), | 3304 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_square_add"); | 3305 | 0 | } | 3306 | 0 | } | 3307 | 0 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_ Line | Count | Source | 3146 | 20.8k | { | 3147 | 20.8k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3148 | | | 3149 | 20.8k | if (HasPlookup<Builder>) { | 3150 | 20.8k | unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder }); | 3151 | 20.8k | return; | 3152 | 20.8k | } | 3153 | | | 3154 | | // Sanity checks | 3155 | 0 | left.sanity_check(); | 3156 | 0 | remainder.sanity_check(); | 3157 | 0 | quotient.sanity_check(); | 3158 | 0 | for (auto& el : to_add) { | 3159 | 0 | el.sanity_check(); | 3160 | 0 | } | 3161 | |
| 3162 | 0 | Builder* ctx = left.context == nullptr ? quotient.context : left.context; | 3163 | |
| 3164 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3165 | 0 | max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3166 | 0 | max_b0 += max_b0; | 3167 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3168 | 0 | max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3169 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3170 | 0 | max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3171 | 0 | max_c1 += max_c1; | 3172 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3173 | 0 | max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS); | 3174 | 0 | max_d0 += max_d0; | 3175 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3176 | 0 | max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3177 | 0 | max_d1 += max_d1; | 3178 | |
| 3179 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value; | 3180 | 0 | max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS); | 3181 | |
| 3182 | 0 | const uint512_t max_r1 = max_b0; | 3183 | 0 | const uint512_t max_r2 = max_c0 + max_c1; | 3184 | 0 | const uint512_t max_r3 = max_d0 + max_d1; | 3185 | |
| 3186 | 0 | uint512_t max_a0(0); | 3187 | 0 | uint512_t max_a1(1); | 3188 | 0 | for (size_t i = 0; i < to_add.size(); ++i) { | 3189 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 3190 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 3191 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 3192 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 3193 | 0 | } | 3194 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 3195 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1; | 3196 | |
| 3197 | 0 | uint64_t max_lo_bits = max_lo.get_msb() + 1; | 3198 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 3199 | 0 | if ((max_lo_bits & 1ULL) == 1ULL) { | 3200 | 0 | ++max_lo_bits; | 3201 | 0 | } | 3202 | 0 | if ((max_hi_bits & 1ULL) == 1ULL) { | 3203 | 0 | ++max_hi_bits; | 3204 | 0 | } | 3205 | |
| 3206 | 0 | field_t half(ctx, bb::fr(2).invert()); | 3207 | 0 | field_t two(ctx, bb::fr(2)); | 3208 | 0 | field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 3209 | 0 | field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 3210 | |
| 3211 | 0 | field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 3212 | 0 | field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 3213 | |
| 3214 | 0 | field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 3215 | 0 | field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 3216 | 0 | field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 3217 | 0 | field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 3218 | |
| 3219 | 0 | const field_t b0 = | 3220 | 0 | two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half); | 3221 | |
| 3222 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 3223 | 0 | left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 3224 | 0 | const field_t c1 = | 3225 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half); | 3226 | |
| 3227 | 0 | const field_t d0 = | 3228 | 0 | two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half); | 3229 | |
| 3230 | 0 | const field_t d1 = | 3231 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half); | 3232 | |
| 3233 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 3234 | 0 | left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3235 | |
| 3236 | 0 | const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element); | 3237 | 0 | const field_t r2 = c0.add_two(c_quotient_1, c1); | 3238 | 0 | const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3; | 3239 | |
| 3240 | 0 | field_t carry_lo_0 = r0 * shift_right_2; | 3241 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3242 | 0 | field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2); | 3243 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3244 | |
| 3245 | 0 | for (const auto& add_element : to_add) { | 3246 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 3247 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 3248 | 0 | } | 3249 | |
| 3250 | 0 | field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element, | 3251 | 0 | -(remainder.binary_basis_limbs[3].element * shift_1)); | 3252 | 0 | field_t carry_hi_0 = r2 * shift_right_2; | 3253 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3254 | 0 | field_t carry_hi_2 = t1 * shift_right_2; | 3255 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3256 | |
| 3257 | 0 | for (const auto& add_element : to_add) { | 3258 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 3259 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 3260 | 0 | } | 3261 | |
| 3262 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3263 | 0 | field_t<Builder> linear_terms = -remainder.prime_basis_limb; | 3264 | 0 | if (to_add.size() >= 2) { | 3265 | 0 | for (size_t i = 0; i < to_add.size() / 2; i += 1) { | 3266 | 0 | linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb); | 3267 | 0 | } | 3268 | 0 | } | 3269 | 0 | if ((to_add.size() & 1UL) == 1UL) { | 3270 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 3271 | 0 | } | 3272 | 0 | field_t<Builder>::evaluate_polynomial_identity( | 3273 | 0 | left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3274 | |
| 3275 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3276 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3277 | |
| 3278 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3279 | 0 | if constexpr (HasPlookup<Builder>) { | 3280 | 0 | carry_lo = carry_lo.normalize(); | 3281 | 0 | carry_hi = carry_hi.normalize(); | 3282 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb)); | 3283 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb)); | 3284 | |
| 3285 | 0 | } else { | 3286 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3287 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3288 | 0 | carry_combined = carry_combined.normalize(); | 3289 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3290 | 0 | carry_combined.get_normalized_witness_index(), | 3291 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3292 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_square_add."); | 3293 | 0 | field_t<Builder> accumulator_midpoint = | 3294 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3295 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3296 | 0 | } else { | 3297 | 0 | carry_lo = carry_lo.normalize(); | 3298 | 0 | carry_hi = carry_hi.normalize(); | 3299 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 3300 | 0 | static_cast<size_t>(carry_lo_msb), | 3301 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_square_add."); | 3302 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 3303 | 0 | static_cast<size_t>(carry_hi_msb), | 3304 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_square_add"); | 3305 | 0 | } | 3306 | 0 | } | 3307 | 0 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ Line | Count | Source | 3146 | 1.31k | { | 3147 | 1.31k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3148 | | | 3149 | 1.31k | if (HasPlookup<Builder>) { | 3150 | 1.31k | unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder }); | 3151 | 1.31k | return; | 3152 | 1.31k | } | 3153 | | | 3154 | | // Sanity checks | 3155 | 0 | left.sanity_check(); | 3156 | 0 | remainder.sanity_check(); | 3157 | 0 | quotient.sanity_check(); | 3158 | 0 | for (auto& el : to_add) { | 3159 | 0 | el.sanity_check(); | 3160 | 0 | } | 3161 | |
| 3162 | 0 | Builder* ctx = left.context == nullptr ? quotient.context : left.context; | 3163 | |
| 3164 | 0 | uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3165 | 0 | max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3166 | 0 | max_b0 += max_b0; | 3167 | 0 | uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3168 | 0 | max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS); | 3169 | 0 | uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3170 | 0 | max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3171 | 0 | max_c1 += max_c1; | 3172 | 0 | uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value); | 3173 | 0 | max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS); | 3174 | 0 | max_d0 += max_d0; | 3175 | 0 | uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value); | 3176 | 0 | max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS); | 3177 | 0 | max_d1 += max_d1; | 3178 | |
| 3179 | 0 | uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value; | 3180 | 0 | max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS); | 3181 | |
| 3182 | 0 | const uint512_t max_r1 = max_b0; | 3183 | 0 | const uint512_t max_r2 = max_c0 + max_c1; | 3184 | 0 | const uint512_t max_r3 = max_d0 + max_d1; | 3185 | |
| 3186 | 0 | uint512_t max_a0(0); | 3187 | 0 | uint512_t max_a1(1); | 3188 | 0 | for (size_t i = 0; i < to_add.size(); ++i) { | 3189 | 0 | max_a0 += to_add[i].binary_basis_limbs[0].maximum_value + | 3190 | 0 | (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS); | 3191 | 0 | max_a1 += to_add[i].binary_basis_limbs[2].maximum_value + | 3192 | 0 | (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS); | 3193 | 0 | } | 3194 | 0 | const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0; | 3195 | 0 | const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1; | 3196 | |
| 3197 | 0 | uint64_t max_lo_bits = max_lo.get_msb() + 1; | 3198 | 0 | uint64_t max_hi_bits = max_hi.get_msb() + 1; | 3199 | 0 | if ((max_lo_bits & 1ULL) == 1ULL) { | 3200 | 0 | ++max_lo_bits; | 3201 | 0 | } | 3202 | 0 | if ((max_hi_bits & 1ULL) == 1ULL) { | 3203 | 0 | ++max_hi_bits; | 3204 | 0 | } | 3205 | |
| 3206 | 0 | field_t half(ctx, bb::fr(2).invert()); | 3207 | 0 | field_t two(ctx, bb::fr(2)); | 3208 | 0 | field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]); | 3209 | 0 | field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]); | 3210 | |
| 3211 | 0 | field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]); | 3212 | 0 | field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]); | 3213 | |
| 3214 | 0 | field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]); | 3215 | 0 | field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]); | 3216 | 0 | field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]); | 3217 | 0 | field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]); | 3218 | |
| 3219 | 0 | const field_t b0 = | 3220 | 0 | two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half); | 3221 | |
| 3222 | 0 | const field_t c0 = left.binary_basis_limbs[1].element.madd( | 3223 | 0 | left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]); | 3224 | 0 | const field_t c1 = | 3225 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half); | 3226 | |
| 3227 | 0 | const field_t d0 = | 3228 | 0 | two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half); | 3229 | |
| 3230 | 0 | const field_t d1 = | 3231 | 0 | two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half); | 3232 | |
| 3233 | 0 | const field_t r0 = left.binary_basis_limbs[0].element.madd( | 3234 | 0 | left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]); | 3235 | |
| 3236 | 0 | const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element); | 3237 | 0 | const field_t r2 = c0.add_two(c_quotient_1, c1); | 3238 | 0 | const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3; | 3239 | |
| 3240 | 0 | field_t carry_lo_0 = r0 * shift_right_2; | 3241 | 0 | field_t carry_lo_1 = r1 * (shift_1 * shift_right_2); | 3242 | 0 | field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2); | 3243 | 0 | field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2); | 3244 | |
| 3245 | 0 | for (const auto& add_element : to_add) { | 3246 | 0 | carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2, | 3247 | 0 | add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2)); | 3248 | 0 | } | 3249 | |
| 3250 | 0 | field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element, | 3251 | 0 | -(remainder.binary_basis_limbs[3].element * shift_1)); | 3252 | 0 | field_t carry_hi_0 = r2 * shift_right_2; | 3253 | 0 | field_t carry_hi_1 = r3 * (shift_1 * shift_right_2); | 3254 | 0 | field_t carry_hi_2 = t1 * shift_right_2; | 3255 | 0 | field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2); | 3256 | |
| 3257 | 0 | for (const auto& add_element : to_add) { | 3258 | 0 | carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2, | 3259 | 0 | add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2)); | 3260 | 0 | } | 3261 | |
| 3262 | 0 | bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus)); | 3263 | 0 | field_t<Builder> linear_terms = -remainder.prime_basis_limb; | 3264 | 0 | if (to_add.size() >= 2) { | 3265 | 0 | for (size_t i = 0; i < to_add.size() / 2; i += 1) { | 3266 | 0 | linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb); | 3267 | 0 | } | 3268 | 0 | } | 3269 | 0 | if ((to_add.size() & 1UL) == 1UL) { | 3270 | 0 | linear_terms += to_add[to_add.size() - 1].prime_basis_limb; | 3271 | 0 | } | 3272 | 0 | field_t<Builder>::evaluate_polynomial_identity( | 3273 | 0 | left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms); | 3274 | |
| 3275 | 0 | const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); | 3276 | 0 | const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); | 3277 | |
| 3278 | 0 | const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb)); | 3279 | 0 | if constexpr (HasPlookup<Builder>) { | 3280 | 0 | carry_lo = carry_lo.normalize(); | 3281 | 0 | carry_hi = carry_hi.normalize(); | 3282 | 0 | ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb)); | 3283 | 0 | ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb)); | 3284 | |
| 3285 | 0 | } else { | 3286 | 0 | if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) { | 3287 | 0 | field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift); | 3288 | 0 | carry_combined = carry_combined.normalize(); | 3289 | 0 | const auto accumulators = ctx->decompose_into_base4_accumulators( | 3290 | 0 | carry_combined.get_normalized_witness_index(), | 3291 | 0 | static_cast<size_t>(carry_lo_msb + carry_hi_msb), | 3292 | 0 | "bigfield: carry_combined too large in unsafe_evaluate_square_add."); | 3293 | 0 | field_t<Builder> accumulator_midpoint = | 3294 | 0 | field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]); | 3295 | 0 | carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed"); | 3296 | 0 | } else { | 3297 | 0 | carry_lo = carry_lo.normalize(); | 3298 | 0 | carry_hi = carry_hi.normalize(); | 3299 | 0 | ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(), | 3300 | 0 | static_cast<size_t>(carry_lo_msb), | 3301 | 0 | "bigfield: carry_lo too large in unsafe_evaluate_square_add."); | 3302 | 0 | ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(), | 3303 | 0 | static_cast<size_t>(carry_hi_msb), | 3304 | 0 | "bigfield: carry_hi too large in unsafe_evaluate_square_add"); | 3305 | 0 | } | 3306 | 0 | } | 3307 | 0 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_ |
3308 | | |
3309 | | template <typename Builder, typename T> |
3310 | | std::pair<uint512_t, uint512_t> bigfield<Builder, T>::compute_quotient_remainder_values( |
3311 | | const bigfield& a, const bigfield& b, const std::vector<bigfield>& to_add) |
3312 | 222k | { |
3313 | 222k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
3314 | | |
3315 | 0 | uint512_t add_values(0); |
3316 | 0 | for (const auto& add_element : to_add) { |
3317 | 0 | add_element.reduction_check(); |
3318 | 0 | add_values += add_element.get_value(); |
3319 | 0 | } |
3320 | |
|
3321 | 0 | const uint1024_t left(a.get_value()); |
3322 | 0 | const uint1024_t right(b.get_value()); |
3323 | 0 | const uint1024_t add_right(add_values); |
3324 | 0 | const uint1024_t modulus(target_basis.modulus); |
3325 | |
|
3326 | 0 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); |
3327 | |
|
3328 | 0 | return { quotient_1024.lo, remainder_1024.lo }; |
3329 | 222k | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE Line | Count | Source | 3312 | 215k | { | 3313 | 215k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 215k | uint512_t add_values(0); | 3316 | 215k | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 215k | const uint1024_t left(a.get_value()); | 3322 | 215k | const uint1024_t right(b.get_value()); | 3323 | 215k | const uint1024_t add_right(add_values); | 3324 | 215k | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 215k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 215k | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 215k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE Line | Count | Source | 3312 | 38 | { | 3313 | 38 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 38 | uint512_t add_values(0); | 3316 | 38 | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 38 | const uint1024_t left(a.get_value()); | 3322 | 38 | const uint1024_t right(b.get_value()); | 3323 | 38 | const uint1024_t add_right(add_values); | 3324 | 38 | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 38 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 38 | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 38 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE Line | Count | Source | 3312 | 20 | { | 3313 | 20 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 20 | uint512_t add_values(0); | 3316 | 20 | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 20 | const uint1024_t left(a.get_value()); | 3322 | 20 | const uint1024_t right(b.get_value()); | 3323 | 20 | const uint1024_t add_right(add_values); | 3324 | 20 | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 20 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 20 | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 20 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 3312 | 255 | { | 3313 | 255 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 255 | uint512_t add_values(0); | 3316 | 255 | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 255 | const uint1024_t left(a.get_value()); | 3322 | 255 | const uint1024_t right(b.get_value()); | 3323 | 255 | const uint1024_t add_right(add_values); | 3324 | 255 | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 255 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 255 | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 255 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 3312 | 1 | { | 3313 | 1 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 1 | uint512_t add_values(0); | 3316 | 1 | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 1 | const uint1024_t left(a.get_value()); | 3322 | 1 | const uint1024_t right(b.get_value()); | 3323 | 1 | const uint1024_t add_right(add_values); | 3324 | 1 | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 1 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 1 | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 1 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE Line | Count | Source | 3312 | 6.19k | { | 3313 | 6.19k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 6.19k | uint512_t add_values(0); | 3316 | 6.19k | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 6.19k | const uint1024_t left(a.get_value()); | 3322 | 6.19k | const uint1024_t right(b.get_value()); | 3323 | 6.19k | const uint1024_t add_right(add_values); | 3324 | 6.19k | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 6.19k | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 6.19k | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 6.19k | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE Line | Count | Source | 3312 | 51 | { | 3313 | 51 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3314 | | | 3315 | 51 | uint512_t add_values(0); | 3316 | 51 | for (const auto& add_element : to_add) { | 3317 | 0 | add_element.reduction_check(); | 3318 | 0 | add_values += add_element.get_value(); | 3319 | 0 | } | 3320 | | | 3321 | 51 | const uint1024_t left(a.get_value()); | 3322 | 51 | const uint1024_t right(b.get_value()); | 3323 | 51 | const uint1024_t add_right(add_values); | 3324 | 51 | const uint1024_t modulus(target_basis.modulus); | 3325 | | | 3326 | 51 | const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus); | 3327 | | | 3328 | 51 | return { quotient_1024.lo, remainder_1024.lo }; | 3329 | 51 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE |
3330 | | |
3331 | | template <typename Builder, typename T> |
3332 | | uint512_t bigfield<Builder, T>::compute_maximum_quotient_value(const std::vector<uint512_t>& as, |
3333 | | const std::vector<uint512_t>& bs, |
3334 | | const std::vector<uint512_t>& to_add) |
3335 | 1.20M | { |
3336 | 1.20M | ASSERT(as.size() == bs.size()); |
3337 | 1.20M | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
3338 | | |
3339 | 0 | uint512_t add_values(0); |
3340 | 1.69M | for (const auto& add_element : to_add) { |
3341 | 1.69M | add_values += add_element; |
3342 | 1.69M | } |
3343 | 0 | uint1024_t product_sum(0); |
3344 | 2.86M | for (size_t i = 0; i < as.size(); i++) { |
3345 | 1.66M | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); |
3346 | 1.66M | } |
3347 | 0 | const uint1024_t add_right(add_values); |
3348 | 0 | const uint1024_t modulus(target_basis.modulus); |
3349 | |
|
3350 | 0 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); |
3351 | |
|
3352 | 0 | return quotient_1024.lo; |
3353 | 0 | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_ Line | Count | Source | 3335 | 1.10M | { | 3336 | 1.10M | ASSERT(as.size() == bs.size()); | 3337 | 1.10M | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 1.10M | uint512_t add_values(0); | 3340 | 1.56M | for (const auto& add_element : to_add) { | 3341 | 1.56M | add_values += add_element; | 3342 | 1.56M | } | 3343 | 1.10M | uint1024_t product_sum(0); | 3344 | 2.62M | for (size_t i = 0; i < as.size(); i++) { | 3345 | 1.51M | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 1.51M | } | 3347 | 1.10M | const uint1024_t add_right(add_values); | 3348 | 1.10M | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 1.10M | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 1.10M | return quotient_1024.lo; | 3353 | 1.10M | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_ Line | Count | Source | 3335 | 38 | { | 3336 | 38 | ASSERT(as.size() == bs.size()); | 3337 | 38 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 38 | uint512_t add_values(0); | 3340 | 38 | for (const auto& add_element : to_add) { | 3341 | 0 | add_values += add_element; | 3342 | 0 | } | 3343 | 38 | uint1024_t product_sum(0); | 3344 | 76 | for (size_t i = 0; i < as.size(); i++) { | 3345 | 38 | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 38 | } | 3347 | 38 | const uint1024_t add_right(add_values); | 3348 | 38 | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 38 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 38 | return quotient_1024.lo; | 3353 | 38 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_ Line | Count | Source | 3335 | 16 | { | 3336 | 16 | ASSERT(as.size() == bs.size()); | 3337 | 16 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 16 | uint512_t add_values(0); | 3340 | 16 | for (const auto& add_element : to_add) { | 3341 | 0 | add_values += add_element; | 3342 | 0 | } | 3343 | 16 | uint1024_t product_sum(0); | 3344 | 32 | for (size_t i = 0; i < as.size(); i++) { | 3345 | 16 | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 16 | } | 3347 | 16 | const uint1024_t add_right(add_values); | 3348 | 16 | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 16 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 16 | return quotient_1024.lo; | 3353 | 16 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ Line | Count | Source | 3335 | 4.01k | { | 3336 | 4.01k | ASSERT(as.size() == bs.size()); | 3337 | 4.01k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 4.01k | uint512_t add_values(0); | 3340 | 5.10k | for (const auto& add_element : to_add) { | 3341 | 5.10k | add_values += add_element; | 3342 | 5.10k | } | 3343 | 4.01k | uint1024_t product_sum(0); | 3344 | 9.88k | for (size_t i = 0; i < as.size(); i++) { | 3345 | 5.87k | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 5.87k | } | 3347 | 4.01k | const uint1024_t add_right(add_values); | 3348 | 4.01k | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 4.01k | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 4.01k | return quotient_1024.lo; | 3353 | 4.01k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ Line | Count | Source | 3335 | 27 | { | 3336 | 27 | ASSERT(as.size() == bs.size()); | 3337 | 27 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 27 | uint512_t add_values(0); | 3340 | 27 | for (const auto& add_element : to_add) { | 3341 | 26 | add_values += add_element; | 3342 | 26 | } | 3343 | 27 | uint1024_t product_sum(0); | 3344 | 54 | for (size_t i = 0; i < as.size(); i++) { | 3345 | 27 | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 27 | } | 3347 | 27 | const uint1024_t add_right(add_values); | 3348 | 27 | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 27 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 27 | return quotient_1024.lo; | 3353 | 27 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_ Line | Count | Source | 3335 | 86.4k | { | 3336 | 86.4k | ASSERT(as.size() == bs.size()); | 3337 | 86.4k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 86.4k | uint512_t add_values(0); | 3340 | 114k | for (const auto& add_element : to_add) { | 3341 | 114k | add_values += add_element; | 3342 | 114k | } | 3343 | 86.4k | uint1024_t product_sum(0); | 3344 | 214k | for (size_t i = 0; i < as.size(); i++) { | 3345 | 128k | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 128k | } | 3347 | 86.4k | const uint1024_t add_right(add_values); | 3348 | 86.4k | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 86.4k | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 86.4k | return quotient_1024.lo; | 3353 | 86.4k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_ Line | Count | Source | 3335 | 576 | { | 3336 | 576 | ASSERT(as.size() == bs.size()); | 3337 | 576 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 576 | uint512_t add_values(0); | 3340 | 576 | for (const auto& add_element : to_add) { | 3341 | 576 | add_values += add_element; | 3342 | 576 | } | 3343 | 576 | uint1024_t product_sum(0); | 3344 | 1.15k | for (size_t i = 0; i < as.size(); i++) { | 3345 | 576 | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 576 | } | 3347 | 576 | const uint1024_t add_right(add_values); | 3348 | 576 | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 576 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 576 | return quotient_1024.lo; | 3353 | 576 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ Line | Count | Source | 3335 | 5.56k | { | 3336 | 5.56k | ASSERT(as.size() == bs.size()); | 3337 | 5.56k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 5.56k | uint512_t add_values(0); | 3340 | 9.04k | for (const auto& add_element : to_add) { | 3341 | 9.04k | add_values += add_element; | 3342 | 9.04k | } | 3343 | 5.56k | uint1024_t product_sum(0); | 3344 | 15.9k | for (size_t i = 0; i < as.size(); i++) { | 3345 | 10.3k | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 10.3k | } | 3347 | 5.56k | const uint1024_t add_right(add_values); | 3348 | 5.56k | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 5.56k | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 5.56k | return quotient_1024.lo; | 3353 | 5.56k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ Line | Count | Source | 3335 | 10 | { | 3336 | 10 | ASSERT(as.size() == bs.size()); | 3337 | 10 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3338 | | | 3339 | 10 | uint512_t add_values(0); | 3340 | 10 | for (const auto& add_element : to_add) { | 3341 | 10 | add_values += add_element; | 3342 | 10 | } | 3343 | 10 | uint1024_t product_sum(0); | 3344 | 20 | for (size_t i = 0; i < as.size(); i++) { | 3345 | 10 | product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]); | 3346 | 10 | } | 3347 | 10 | const uint1024_t add_right(add_values); | 3348 | 10 | const uint1024_t modulus(target_basis.modulus); | 3349 | | | 3350 | 10 | const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus); | 3351 | | | 3352 | 10 | return quotient_1024.lo; | 3353 | 10 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_ Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_ |
3354 | | template <typename Builder, typename T> |
3355 | | std::pair<bool, size_t> bigfield<Builder, T>::get_quotient_reduction_info(const std::vector<uint512_t>& as_max, |
3356 | | const std::vector<uint512_t>& bs_max, |
3357 | | const std::vector<bigfield>& to_add, |
3358 | | const std::vector<uint1024_t>& remainders_max) |
3359 | 1.20M | { |
3360 | 1.20M | ASSERT(as_max.size() == bs_max.size()); |
3361 | | |
3362 | 1.20M | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); |
3363 | 1.20M | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); |
3364 | 1.20M | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); |
3365 | | |
3366 | | // Check if the product sum can overflow CRT modulus |
3367 | 1.20M | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { |
3368 | 0 | return std::pair<bool, size_t>(true, 0); |
3369 | 0 | } |
3370 | 1.20M | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); |
3371 | 1.20M | std::vector<uint512_t> to_add_max; |
3372 | 1.69M | for (auto& added_element : to_add) { |
3373 | 1.69M | to_add_max.push_back(added_element.get_maximum_value()); |
3374 | 1.69M | } |
3375 | | // Get maximum value of quotient |
3376 | 1.20M | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); |
3377 | | |
3378 | | // Check if the quotient can fit into the range proof |
3379 | 1.20M | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { |
3380 | 5 | return std::pair<bool, size_t>(true, 0); |
3381 | 5 | } |
3382 | 1.20M | return std::pair<bool, size_t>(false, num_quotient_bits); |
3383 | 1.20M | } _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE Line | Count | Source | 3359 | 1.10M | { | 3360 | 1.10M | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 1.10M | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 1.10M | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 1.10M | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 1.10M | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 1.10M | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 1.10M | std::vector<uint512_t> to_add_max; | 3372 | 1.56M | for (auto& added_element : to_add) { | 3373 | 1.56M | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 1.56M | } | 3375 | | // Get maximum value of quotient | 3376 | 1.10M | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 1.10M | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 5 | return std::pair<bool, size_t>(true, 0); | 3381 | 5 | } | 3382 | 1.10M | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 1.10M | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE Line | Count | Source | 3359 | 38 | { | 3360 | 38 | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 38 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 38 | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 38 | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 38 | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 38 | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 38 | std::vector<uint512_t> to_add_max; | 3372 | 38 | for (auto& added_element : to_add) { | 3373 | 0 | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 0 | } | 3375 | | // Get maximum value of quotient | 3376 | 38 | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 38 | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 38 | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 38 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE Line | Count | Source | 3359 | 16 | { | 3360 | 16 | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 16 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 16 | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 16 | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 16 | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 16 | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 16 | std::vector<uint512_t> to_add_max; | 3372 | 16 | for (auto& added_element : to_add) { | 3373 | 0 | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 0 | } | 3375 | | // Get maximum value of quotient | 3376 | 16 | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 16 | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 16 | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 16 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE Line | Count | Source | 3359 | 4.01k | { | 3360 | 4.01k | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 4.01k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 4.01k | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 4.01k | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 4.01k | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 4.01k | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 4.01k | std::vector<uint512_t> to_add_max; | 3372 | 5.10k | for (auto& added_element : to_add) { | 3373 | 5.10k | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 5.10k | } | 3375 | | // Get maximum value of quotient | 3376 | 4.01k | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 4.01k | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 4.01k | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 4.01k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE Line | Count | Source | 3359 | 27 | { | 3360 | 27 | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 27 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 27 | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 27 | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 27 | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 27 | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 27 | std::vector<uint512_t> to_add_max; | 3372 | 27 | for (auto& added_element : to_add) { | 3373 | 26 | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 26 | } | 3375 | | // Get maximum value of quotient | 3376 | 27 | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 27 | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 27 | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 27 | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE Line | Count | Source | 3359 | 86.4k | { | 3360 | 86.4k | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 86.4k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 86.4k | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 86.4k | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 86.4k | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 86.4k | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 86.4k | std::vector<uint512_t> to_add_max; | 3372 | 114k | for (auto& added_element : to_add) { | 3373 | 114k | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 114k | } | 3375 | | // Get maximum value of quotient | 3376 | 86.4k | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 86.4k | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 86.4k | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 86.4k | } |
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE Line | Count | Source | 3359 | 576 | { | 3360 | 576 | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 576 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 576 | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 576 | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 576 | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 576 | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 576 | std::vector<uint512_t> to_add_max; | 3372 | 576 | for (auto& added_element : to_add) { | 3373 | 576 | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 576 | } | 3375 | | // Get maximum value of quotient | 3376 | 576 | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 576 | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 576 | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 576 | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE Line | Count | Source | 3359 | 5.56k | { | 3360 | 5.56k | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 5.56k | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 5.56k | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 5.56k | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 5.56k | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 5.56k | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 5.56k | std::vector<uint512_t> to_add_max; | 3372 | 9.04k | for (auto& added_element : to_add) { | 3373 | 9.04k | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 9.04k | } | 3375 | | // Get maximum value of quotient | 3376 | 5.56k | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 5.56k | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 5.56k | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 5.56k | } |
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE Line | Count | Source | 3359 | 10 | { | 3360 | 10 | ASSERT(as_max.size() == bs_max.size()); | 3361 | | | 3362 | 10 | ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT); | 3363 | 10 | ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3364 | 10 | ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT); | 3365 | | | 3366 | | // Check if the product sum can overflow CRT modulus | 3367 | 10 | if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) { | 3368 | 0 | return std::pair<bool, size_t>(true, 0); | 3369 | 0 | } | 3370 | 10 | const size_t num_quotient_bits = get_quotient_max_bits(remainders_max); | 3371 | 10 | std::vector<uint512_t> to_add_max; | 3372 | 10 | for (auto& added_element : to_add) { | 3373 | 10 | to_add_max.push_back(added_element.get_maximum_value()); | 3374 | 10 | } | 3375 | | // Get maximum value of quotient | 3376 | 10 | const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max); | 3377 | | | 3378 | | // Check if the quotient can fit into the range proof | 3379 | 10 | if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) { | 3380 | 0 | return std::pair<bool, size_t>(true, 0); | 3381 | 0 | } | 3382 | 10 | return std::pair<bool, size_t>(false, num_quotient_bits); | 3383 | 10 | } |
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE |
3384 | | |
3385 | | } // namespace bb::stdlib |